Abschlussprojekt - Data Analytics¶

Das Abschlussprojekt besteht aus zwei Teilen:

                                            1. Teil - Datenanalyse
                                            2. Teil - Dashboard

Vorweg: Hinweise und Organisation

Grobe Zusammenfassung der am Freitag besprochenen Anforderungen:

            - vollständige Datenaufbereitung
            - Dokumentation der Arbeitsschritte (in englisch oder deutsch)
            - nachvollziehbare und aussagekräftige Erläuterungen über Vorgehensweise/Entscheidungen
            - für die Bewertung: 3 verschiedenartige Plots (Plotfunktionen) benennen 
              (Plot 1: univariate Analyse, Plot 2: bivariate Analyse, Plot 3: multivariate Analyse)
            - Customizing der Plots
            - Analyse der Plots
            - Coding

Für die Visualisierung haben wir die Bibliothek Plotly express bzw Plotly kennen gelernt.

Für den Fall, dass du in der EDA die Bibliothek Matplotlib verwenden möchtest, gelten folgende Anforderungen:

          - objektorientierte Stil verwenden https://matplotlib.org/stable/users/explain/api_interfaces.html
          - benötigte high-level Bibliotheken sind selbstständig zu recherchieren, zu installieren und einzuarbeiten
          - für die EDA ist ein- und dieselbe Bibliothek zu verwenden 

Treff ist Donnerstag um 14:30 Uhr im Hauptraum. Da werden wir die Unterlagen in dokumentensichere Formate umwandeln. Das machen wir zusammen. Danach habt ihr bis 15:30 Uhr zeit, eure zu bewertenden Unterlagen in den Projektabgabeordner hochzuladen.

Am Freitag erfolgt die Vorstellung der 3 Plots innerhalb des Zeitrahmens von 5min - (+-1min) ist dabei ok. Bewertet wird die Einhaltung des Zeitrahmes - dass das Anliegen innerhalb eines vorgegebenen Zeitrahmens vorgetragen wird.

1. Teil - Datenanalyse¶

Du arbeitest als Data Scientist bei der P-2-P-Plattform https://www.kiva.org/, die vor einem Jahr gegründet wurde. Nun wollt ihr euer Geschäft erweitern. Euer Team hat sich aufgeteilt und jeder Analyst hat einen Teilbereich der Daten. Deine Aufgabe ist es in einer explorativen Datenanalyse Insights für eure Plattform herauszufinden.

CRISP DM: Business Understanding¶

Euer Geschäftsmodell ist das Betreiben einer Plattform (crowd-investing) bei der sich Personen die eine Geschäftsidee haben, aber nicht das benötigte Geld, anmelden und für ihr Projekt innerhalb einer vorgegebenen Zeit Geld sammeln können.

Auf der anderen Seite habt ihr Geldgeber, die gern ihr Geld in Projekte anlegen möchten und nach Investitionen suchen.

Als Vermittler bringt eure Plattform also Geldnehmer und Geldgeber zusammen.

Deine Datenbasis ist die Historie eurer Plattform.

Getroffene Annahmen zu dem Geschäftsmodell

Alle Projekte sind abgeschlossene Projekte, d.h. die Zeit, um für sein Projekt Geld zu sammeln ist abgelaufen. Euer Geschäftsmodell sieht es vor, dass die gesammelten Gelder ausgezahlt werden, auch wenn der Zielbetrag nicht erreicht wurde.

Ihr verdient euer Geld mit einer Provision für jedes Projekt was auf eurer Plattform landet.

Der Geldgeber erhält einen Zins für die Geldleihe.

CRISP DM: Data Understanding¶

- funded_amount ... mit Ablauf der "Crowding"zeit erhaltener Betrag/ ausgezahlter Betrag in USD
- loan_amount ... Zielbetrag (Betrag dem man für das Projekt erreichen wollte) in USD
- activity ... Unterkategory zu dem das Ziel des Crowdprojektes thematisch gehört
- sector ... Oberkategory in den das Crowdprojektes Thema fällt
- use ... Kurzbeschreibung wofür das Geld verwendet werden soll
- country_code ... Ländercode nach ISO Norm
- country ... Ländername nach ISO Norm
- region ... Region
- currency ... Währung in den der funded_amount dann ausgezahlt wurde
- term in months ... Dauer über die der Kredit ausgezahlt werden soll
- lender_count ...Darlehensgeber (also wieviele Personen Geld für das Projekt gegeben haben)
- borrower_genders ... Geschlecht und Anzahl der Darlehensnehmer, also diejenigen die das Crowdprojekt initiiert haben       
- repayment interval ... vertraglich vereinbarte Rückzahlungsmodalitäten/-rhythmus

2. Teil - Dashboard¶

Basierend auf den vorangegangenen Daten soll ein Dashboard erstellt werden.

Das Dashboard soll:

                - mindestens 1 HTML component enthalten
                - 1 Dash Core Component mit dem Daten ausgewählt werden können
                - 1 Grafik, die sich in Abhängigkeit von der Datenauswahl ändert

Buissnes Understanding Erweiterte Recherche¶

Geschäftsablauf¶

  • Ein oder mehrere Personen, üblicherweise aus unterentwickelten Ländern aber auch aus den USA, beantragt einen Kredit für ein Projekt.
  • Dies wird oft von einem Partner von Kiva, einer NCO, einem MFI (Microfinance Institution) und anderen Trustees angelegt. Direktkredite sind auch möglich.
  • Die potenzeillen Kreditgeber sehen sich die Geschichte und das Geschäftsmodell an und investieren bis zum vollen angefragten Betrag in 25 Dolar Schritten.
  • Diese werden meistens über den Partner an den Kreditnehmer ausbezahlt.
  • Der Kreditnehmer investiert den Kredit in das Projekt um seine Geschäftsidee zu ermöglichen.
  • 96,4% aller Kredite werden zurückgezahlt.
  • Wenn der Kreditgeber die Kreditsumme nicht direkt vollständig zurückfordert wird Kiva das Geld in andere Projekte reinvestieren.

Zielländer¶

  • 70 Länder in 5 Kontinenten

Repaiment (Eigenauskunft)¶

  • 96,4% von allen Krediten
  • 97% von Krediten in denen ein Partener von Kiva involviert war.
  • 73,7% von direkten Krediten an Kreditnehmer aus den US.
  • Alle Risiken werden von den Kreditoren getragen.
  • Risikofelder sind: Geschäftsidee klapt nicht, Gesundheit des Kreditnehmers verschlechtert sich, Diebstahl, Höhere Gewalt, Änderung des Marktumfeldes, Überschuldung, Politische Lage im Zielland verschlächtert sich, Kiva Partner geht Bankrot oder Betrügt, Logistische Probleme beim Auszahlen oder Rückzahlung des Lohnes, Währungsumtauschrisiken

Brainstorming / Potenzielle Buissnessfragen¶

  • Woher kommen unsere Debitoren?
  • Wie ist die Verteilung nach Geschlecht?
  • Wie ist die Verteilung nach Rückzahlungsart?
  • Was für Geschäftsideen gibt es?
  • Was wird erfolgreich finanziert?
  • Wie ist die Verteilung der Kreditoren?
  • Was sind Faktoren für einen Erfolgreichen Kredit?

Die interesanteste Buissnessfrage ist es ob ein Kredit zu stande gekommen ist oder nicht, und welche Faktoren dies beinhaltet. Hier möchte ich die Kunden in einzelne Gruppen aufteilen und nach Geschecht, Land und Gruppengröße untersuchen

Ein erfolgreiches Funding liegt im Interesse aller Beteiligter.

Daten Aufbereiten¶

Daten und Bibliotheken einlesen und erkunden¶

In [1]:
# Notwendige Biblioteken Einlesen
import numpy as np
import pandas as pd
import csv
import plotly.express as px
import plotly.graph_objects as go
In [2]:
# Einlesen der Daten

# Automatische feststellung des CSV-Dialektes
with open("data_abschlussprojekt.csv", 'r', newline='') as csv_file:
    dialect = csv.Sniffer().sniff(csv_file.read(2048))
    print("Sniff: ", dialect.delimiter, dialect.doublequote,
          repr(dialect.lineterminator), dialect.quotechar)

# Einlesen in einen Panda DataFrame
df = pd.read_csv("data_abschlussprojekt.csv",
                 on_bad_lines="warn",
                 dialect=dialect,
                 index_col=0)
df
Sniff:  # False '\r\n' "
Out[2]:
funded_amount loan_amount activity sector use country_code country region currency term_in_months lender_count borrower_genders repayment_interval
0 300.0 300.0 Fruits & Vegetables Food To buy seasonal, fresh fruits to sell. PK Pakistan Lahore PKR 12.0 12 female irregular
1 575.0 575.0 Rickshaw Transportation to repair and maintain the auto rickshaw used ... PK Pakistan Lahore PKR 11.0 14 female, female irregular
2 150.0 150.0 Transportation Transportation To repair their old cycle-van and buy another ... IN India Maynaguri INR 43.0 6 female bullet
3 200.0 200.0 Embroidery Arts to purchase an embroidery machine and a variet... PK Pakistan Lahore PKR 11.0 8 female irregular
4 400.0 400.0 Milk Sales Food to purchase one buffalo. PK Pakistan Abdul Hakeem PKR 14.0 16 female monthly
... ... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture [True, u'para compara: cemento, arenya y ladri... PY Paraguay Concepción USD 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment NaN KE Kenya NaN KES 13.0 0 NaN monthly
671203 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly

671205 rows × 13 columns

In [3]:
# Erste Infos ermitteln
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 671205 entries, 0 to 671204
Data columns (total 13 columns):
 #   Column              Non-Null Count   Dtype  
---  ------              --------------   -----  
 0   funded_amount       671205 non-null  float64
 1   loan_amount         671205 non-null  float64
 2   activity            671205 non-null  object 
 3   sector              671205 non-null  object 
 4   use                 666972 non-null  object 
 5   country_code        671197 non-null  object 
 6   country             671205 non-null  object 
 7   region              614405 non-null  object 
 8   currency            671205 non-null  object 
 9   term_in_months      671205 non-null  float64
 10  lender_count        671205 non-null  int64  
 11  borrower_genders    666984 non-null  object 
 12  repayment_interval  671205 non-null  object 
dtypes: float64(3), int64(1), object(9)
memory usage: 71.7+ MB

Der Datensatz enthält Nulldaten aber keine Auffälligkeiten im Datentyp.

In [4]:
# Sind die Spaltennamen richtig Formatiert?
df.columns
Out[4]:
Index(['funded_amount', 'loan_amount', 'activity', 'sector', 'use',
       'country_code', 'country', 'region', 'currency', 'term_in_months',
       'lender_count', 'borrower_genders', 'repayment_interval'],
      dtype='object')

Die Columns des Datensatzen enthalten keine Besonderheiten

In [5]:
# Beschreiben der Daten inkl. kategorischer Daten
df.describe(include='all')
Out[5]:
funded_amount loan_amount activity sector use country_code country region currency term_in_months lender_count borrower_genders repayment_interval
count 671205.000000 671205.000000 671205 671205 666972 671197 671205 614405 671205 671205.000000 671205.000000 666984 671205
unique NaN NaN 163 15 423452 86 87 12695 67 NaN NaN 11298 4
top NaN NaN Farming Agriculture to buy a water filter to provide safe drinking... PH Philippines Kaduna PHP NaN NaN female monthly
freq NaN NaN 72955 180302 5217 160441 160441 10000 160440 NaN NaN 426502 342717
mean 785.995061 842.397107 NaN NaN NaN NaN NaN NaN NaN 13.739022 20.590922 NaN NaN
std 1130.398941 1198.660073 NaN NaN NaN NaN NaN NaN NaN 8.598919 28.459551 NaN NaN
min 0.000000 25.000000 NaN NaN NaN NaN NaN NaN NaN 1.000000 0.000000 NaN NaN
25% 250.000000 275.000000 NaN NaN NaN NaN NaN NaN NaN 8.000000 7.000000 NaN NaN
50% 450.000000 500.000000 NaN NaN NaN NaN NaN NaN NaN 13.000000 13.000000 NaN NaN
75% 900.000000 1000.000000 NaN NaN NaN NaN NaN NaN NaN 14.000000 24.000000 NaN NaN
max 100000.000000 100000.000000 NaN NaN NaN NaN NaN NaN NaN 158.000000 2986.000000 NaN NaN

Für die einzelnen Spalten läst sich feststellen:

funded_amount

  • Keine NaN Werte.
  • Warscheinlich einige sehr hohe Kredite. Der Median ligt bei 450,00 Dolar, der Durschschnitt aber bei 786 Dolar. Mit einem Max von 100000 Dolar. Die IQR liegt bei 900 - 250 = 650 Dolar. Die Standartabweichung ist sehr hoch, was auf eine deutliche Schiefe in der Verteilung hinweist.
  • Es gibt Werte die 0 sind. Dies sollten nicht erfolgreiche Fundings sein. Hier sollt auch lender_count = 0 gelten.

loan_amount

  • Keine NaN Werte.
  • Es gelten änliche Annahmen für die Verteilung wie beim funded_amount.
  • Es gibt keine 0 Werte da es Keine Kredite mit einem 0 Betrag geben solte.
  • Insgesamt sind die statistischen Werte leicht erhöht im vergleich zu funded_amount. Dies ist zu erwarten, da hier auch die nichterfüllten Fundraiser miteinbezogen sind.
  • Der Max ist gleich. Zumindestens ein Kredit mit einer Maximalwunschhöhe von 100000 Dolar wurde auch finanziert.
  • Dies könnte für nachfolgende Fragestellung interesant sein. Eventuell gibt es einen Zusammenhang zwischen gewünschtem Kreditvolumen und dem Funding Erfolg.

activity

  • Keine NaN Werte.
  • Es gibt 163 verschidene Kategorien.
  • Die häufigste Kategorie ist Farming mit 72955 Einträgen (10,8%)

sector

  • Keine NaN
  • Es gibt 15 Kategorien
  • Die häufigste Kategorie ist Agriculture mit 180302 Einträgen (26,9%). Dies ist mit der activity Spalte deckig.
  • Diese Kategoriesierung ist potenziell besser für nachfolgende Auswertung geeignet da sie eine Kondensierung der Kategorien aus activity darstellt und so einen besseren Überblick ermöglicht.

use

  • Enthält NaN Werte.
  • Enthält als Freitext 423452 einzigartige Einträge. Dies mach es ohne Text-Mining schwierig dies Auszuwerten. Eine direkte Auswertung ist aber für unsere Fragestellungen nicht zwingend notwendig da die Informationen in activity und sector schon aggrigiert vorliegen.
  • Interesanterweise ist der Text: to buy a water filter to provide safe drinking... mit 5217 am häufigsten vorhanden.

country_code

  • Enthält NaN Werte.
  • Enthält 86 einzigartige Werte.
  • PH mit 160441 Werten ist der häufigste Wert (23,9%).
  • Kann eventuell fallen gelassen werden da sie eine dopplung der Daten darstellt.

country

  • Enthält keine NaN Werte.
  • Enthält 87 einzigartige Werte. Einer mehr als erwartet.
  • Phillipines is mit 160441 der häufigste Wert (23,9%). Dies deckt sich mit der country_code Spalte.
  • Es ist zu erwegen die country_code Zeile entweder mit den Informationen zu ergänzen oder zu streichen da hier parallell daten gespeichert werden.
  • Das Land ist insgesamt eine interesante Spalte da eventuell das Herkunftsland eine Rolle bei dem erfolgreichen Funding haben könnte.

region

  • Enthält NaN Werte.
  • Enthält 12695 Einzigartige Werte.
  • Kanduna (Nigeria) ist mit 10000 Einträgen der häufigste Wert (1,5)%
  • Diese Zeile ist eventuell zu feingliedrig für unsere Fragestellungen. Auch lässt sich warscheinlich die Region nicht gut im nachhinein automatisch nachtragen.

currency

  • Enthält keine NaN Werte.
  • Enthält 67 einzigartige Werte. Weniger als es Zielländer gibt.
  • PHP (Philippinische Peso) ist mit 160440 häufigster Wert. Dies ist einer zu wenig als erwartet.
  • Diese Spalte ist warscheinlich für unsere Fragestellung erstmal zweitrangig. Währungswechselrisiken betrachen wir erstmal nicht.

term_in_month

  • Enthält keine NaN Werte.
  • Die Range ist mit 1 bis 158 Monaten recht groß mit einer Median von 13 Monaten und einem IQR von 14 - 8 = 6 Monaten. Insgesamt gibt es hier warscheinlich einige Extemwerte. Dies deckt sich auch logisch mit den Extremwerten in der funded_amount Spalte. Eine deutliche Schiefe wird erwartet.
  • Diese Spalte könnte für nachfolgende Fragen interesant sein, da die Laufzeit einen Einfluss auf das Funding haben könnte.

lender_count

  • Enthält keine NaN Werte.
  • Enthält 0 Werte. Diese solten mit der 0 in funded_amount übereinstimmen. Dies ist eventuell zu überprüfen.
  • Der median ist 13 mit einer IQR von 24 - 7 = 17. Mit einem Max von 2986 und einem Durchschnitt von 20,5 und Std-Abweichung von 28,5 wird eine deutliche Schiefe erwartet.
  • Da in unserer Fragestellung erstmal das Funding an sich interesant ist, ist die Anzahl der Funder nicht ganz unwichtig aber wichtiger ist primär ob welche da sind oder nicht.

borrow_gender

  • Enthält NaN Werte.
  • Enthält 11298 einzigartige Werte. Es is angebrach hier noch mal genauer drauf zu schauen.
  • Female ist mit 426502 Einträgen (63,5%) der deutliche am Häufig vorkommende Wert.
  • Diese Spalte ist für unsere Analyse eine interesante Spalte, da sie eventuell einen hohen Einfluss auf das Funding haben könnte.

repayment_interval

  • Enthält keine NaN Werte.
  • Enthält nur 4 Kategorien.
  • Die häufigste Kategorie ist monthly mit 342717 (51,1%).
  • Diese Spalte ist für nachfolgende Analysen eine interesante Spalte, da sie eventuell einen hohen Einfluss auf das Funding haben könnte.

Behandeln von Doppelten Einträgen¶

In [6]:
print("Anzahl Duplikate:",
      df.duplicated().sum(),
      f"\nIn Prozent: {df.duplicated().mean()*100:.2f}%")
Anzahl Duplikate: 24588 
In Prozent: 3.66%

Ansicht eines Auszuges der Duplicate.

In [7]:
df.loc[df.duplicated(), :]
Out[7]:
funded_amount loan_amount activity sector use country_code country region currency term_in_months lender_count borrower_genders repayment_interval
498 100.0 100.0 Home Energy Personal Use to buy a solar-powered lamp. SV El Salvador NaN USD 14.0 4 male monthly
606 100.0 100.0 Home Energy Personal Use to buy a solar-powered lamp. SV El Salvador NaN USD 14.0 4 male monthly
808 450.0 450.0 Higher education costs Education to pay for one semester's registration fees. CO Colombia Bogotà COP 7.0 15 female monthly
1703 500.0 500.0 Higher education costs Education To buy a laptop for educational purposes. SO Somalia Hargeisa USD 8.0 19 male monthly
2317 250.0 250.0 Poultry Agriculture to purchase poultry. KE Kenya Ndaragwa KES 16.0 10 female monthly
... ... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture [True, u'para compara: cemento, arenya y ladri... PY Paraguay Concepción USD 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment NaN KE Kenya NaN KES 13.0 0 NaN monthly
671203 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly

24588 rows × 13 columns

In [8]:
# Duplikate ohne Funding
df.loc[(df.duplicated()) & (df['funded_amount'] == 0), :]
Out[8]:
funded_amount loan_amount activity sector use country_code country region currency term_in_months lender_count borrower_genders repayment_interval
126605 0.0 350.0 Personal Housing Expenses Housing NaN SV El Salvador NaN USD 14.0 0 NaN monthly
126675 0.0 350.0 Personal Housing Expenses Housing NaN SV El Salvador NaN USD 14.0 0 NaN monthly
126788 0.0 125.0 Clothing Clothing NaN KE Kenya NaN KES 3.0 0 NaN bullet
275942 0.0 325.0 Grocery Store Food NaN KE Kenya NaN KES 7.0 0 NaN bullet
280683 0.0 325.0 General Store Retail NaN KE Kenya NaN KES 9.0 0 NaN bullet
... ... ... ... ... ... ... ... ... ... ... ... ... ...
671199 0.0 25.0 Livestock Agriculture [True, u'para compara: cemento, arenya y ladri... PY Paraguay Concepción USD 13.0 0 female monthly
671200 0.0 25.0 Livestock Agriculture [True, u'para compara: cemento, arenya y ladri... PY Paraguay Concepción USD 13.0 0 female monthly
671202 0.0 25.0 Games Entertainment NaN KE Kenya NaN KES 13.0 0 NaN monthly
671203 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture [True, u'to start a turducken farm.'] - this l... KE Kenya NaN KES 13.0 0 female monthly

105 rows × 13 columns

In [9]:
print(f"Prozent von nicht erfolgreichen Duplicaten: {df.loc[(df.duplicated()) & (df['funded_amount'] == 0), :].shape[0] / df.loc[(df.duplicated()) , :].shape[0] * 100: .2f}%")
Prozent von nicht erfolgreichen Duplicaten:  0.43%

Insgesamt gibt es mit 24588 (3,66%) nur recht wenige Duplicate. Davon sind grade einmal 105 (0.43% von 24588) potenzielle Versuche das selbe nach einem nicht erfolgreichem Funding erneut zu funden. Die erfolgreichen doppelten Fundings lassen sich zudem nicht eindeutig als systemseitiger Doppeleintrag identifizieren da eindeutige Identifier wie eine Transaktionsnummer fehlen. Es ist warscheinlich das erfolgreiche Fundings eventuell mehrfach wiederholt wurden.

Deshalb werden die Doppeleinträge im Datensatz behalten.

Behandlung von NaN Werten¶

Spalten mit NaN sind: use, country_code, region, borrow_gender

In [10]:
# Gesamtsumme der NaN Werte
df.isna().sum()
Out[10]:
funded_amount             0
loan_amount               0
activity                  0
sector                    0
use                    4233
country_code              8
country                   0
region                56800
currency                  0
term_in_months            0
lender_count              0
borrower_genders       4221
repayment_interval        0
dtype: int64

Case 'use'¶

Eine behandlung der NaN Werte für use ist nicht notwendig da hier kein Text-Mining vorgenommen wird. Die für uns eventuell wichtige Info über den Verwendungszweck wird schon ausreichend in den Spalten activity und sector eingetragen. Text-Mining wird auserdem dadurch erschwehrt das verschiedene Sprachen verwendet werden. Sollte hier ein Machine Learning im Anschluss erfolgen dass das Verhalten der Kundengruppen anhand des Textes vorhersehen möchte, müßte die Spalte entsprechend aufbereitet werden, was wir hier aber auserhalb unserer technischen Möglichkeiten ist.

Deshalb kann die Spalte für die Analyse rausgenommen werden.

In [11]:
# Spalte use löschen
df.drop(columns="use", inplace=True)
In [12]:
df
Out[12]:
funded_amount loan_amount activity sector country_code country region currency term_in_months lender_count borrower_genders repayment_interval
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan Lahore PKR 12.0 12 female irregular
1 575.0 575.0 Rickshaw Transportation PK Pakistan Lahore PKR 11.0 14 female, female irregular
2 150.0 150.0 Transportation Transportation IN India Maynaguri INR 43.0 6 female bullet
3 200.0 200.0 Embroidery Arts PK Pakistan Lahore PKR 11.0 8 female irregular
4 400.0 400.0 Milk Sales Food PK Pakistan Abdul Hakeem PKR 14.0 16 female monthly
... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay Concepción USD 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture KE Kenya NaN KES 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment KE Kenya NaN KES 13.0 0 NaN monthly
671203 0.0 25.0 Livestock Agriculture KE Kenya NaN KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture KE Kenya NaN KES 13.0 0 female monthly

671205 rows × 12 columns

Case country_code¶

In [13]:
# Auflistung der NaN für county_code
df.loc[df["country_code"].isna(), :]
Out[13]:
funded_amount loan_amount activity sector country_code country region currency term_in_months lender_count borrower_genders repayment_interval
202537 4150.0 4150.0 Wholesale Wholesale NaN Namibia EEnhana NAD 6.0 162 female bullet
202823 4150.0 4150.0 Wholesale Wholesale NaN Namibia Rundu NAD 6.0 159 male bullet
344929 3325.0 3325.0 Wholesale Wholesale NaN Namibia EEnhana NAD 7.0 120 female bullet
351177 3325.0 3325.0 Wholesale Wholesale NaN Namibia Rundu NAD 7.0 126 male bullet
420953 3325.0 3325.0 Wholesale Wholesale NaN Namibia EEnhana NAD 7.0 118 female bullet
421218 4000.0 4000.0 Wholesale Wholesale NaN Namibia Rundu NAD 7.0 150 male bullet
487207 5100.0 5100.0 Renewable Energy Products Retail NaN Namibia Katima Mulilo NAD 7.0 183 male bullet
487653 5000.0 5000.0 Wholesale Wholesale NaN Namibia Oshakati NAD 7.0 183 female bullet
In [14]:
# Auflistung aller Namibia Daten
df.loc[df["country"] == 'Namibia', :]
Out[14]:
funded_amount loan_amount activity sector country_code country region currency term_in_months lender_count borrower_genders repayment_interval
202537 4150.0 4150.0 Wholesale Wholesale NaN Namibia EEnhana NAD 6.0 162 female bullet
202823 4150.0 4150.0 Wholesale Wholesale NaN Namibia Rundu NAD 6.0 159 male bullet
344929 3325.0 3325.0 Wholesale Wholesale NaN Namibia EEnhana NAD 7.0 120 female bullet
351177 3325.0 3325.0 Wholesale Wholesale NaN Namibia Rundu NAD 7.0 126 male bullet
420953 3325.0 3325.0 Wholesale Wholesale NaN Namibia EEnhana NAD 7.0 118 female bullet
421218 4000.0 4000.0 Wholesale Wholesale NaN Namibia Rundu NAD 7.0 150 male bullet
487207 5100.0 5100.0 Renewable Energy Products Retail NaN Namibia Katima Mulilo NAD 7.0 183 male bullet
487653 5000.0 5000.0 Wholesale Wholesale NaN Namibia Oshakati NAD 7.0 183 female bullet

Die NaN Werte in der Spalte country_code sind ausschlieslich für den Fall zu finden in dem country = Namibia gilt. Da der Ländercode für Namibia 'Na' ist, könnte hier ein Fehler beim Importieren passiert sein. Eventuell hat das System Na nicht richtig erkannt und mit einem Synonym für Null, NaN etc. verwechselt.

Desweiteren ist die country_code Spalte inhaltlich eine Kopie von country. Sie ist also theoretisch obsolet könnte aber für einen Geoplot noch verwendung finden .

Die Spalte country_code wird korrigiert und trotz dopplung behalten

In [15]:
# Korrigieren der NaN für Namibia
df.loc[df["country"] == 'Namibia', 'country_code'] = 'NA'
df.loc[df["country"] == 'Namibia', :]
Out[15]:
funded_amount loan_amount activity sector country_code country region currency term_in_months lender_count borrower_genders repayment_interval
202537 4150.0 4150.0 Wholesale Wholesale NA Namibia EEnhana NAD 6.0 162 female bullet
202823 4150.0 4150.0 Wholesale Wholesale NA Namibia Rundu NAD 6.0 159 male bullet
344929 3325.0 3325.0 Wholesale Wholesale NA Namibia EEnhana NAD 7.0 120 female bullet
351177 3325.0 3325.0 Wholesale Wholesale NA Namibia Rundu NAD 7.0 126 male bullet
420953 3325.0 3325.0 Wholesale Wholesale NA Namibia EEnhana NAD 7.0 118 female bullet
421218 4000.0 4000.0 Wholesale Wholesale NA Namibia Rundu NAD 7.0 150 male bullet
487207 5100.0 5100.0 Renewable Energy Products Retail NA Namibia Katima Mulilo NAD 7.0 183 male bullet
487653 5000.0 5000.0 Wholesale Wholesale NA Namibia Oshakati NAD 7.0 183 female bullet

Case region¶

In [16]:
# Welche einzigartigen Regionen mit NaN Werten gibt es
pd.unique(df.loc[df['region'].isna(), 'country'])
Out[16]:
array(['Kenya', 'El Salvador', 'Senegal', 'Iraq', 'United States', 'Peru',
       'Tanzania', 'Guatemala', 'Colombia', 'Indonesia', 'Kosovo',
       'Timor-Leste', 'Turkey', 'Philippines', 'Palestine', 'Burundi',
       'Tajikistan', 'Honduras', 'Jordan', 'Mexico', 'Lebanon', 'Albania',
       'Nicaragua', 'Bolivia', 'Israel', 'Rwanda', 'Azerbaijan',
       'Ecuador', 'Mongolia', 'Haiti', 'Cambodia', 'Sierra Leone',
       'Yemen', 'Zimbabwe', 'Paraguay', 'Uganda', 'Armenia',
       'Dominican Republic', 'Benin', 'Belize', 'Ghana', 'Mozambique',
       'Zambia', 'Samoa', 'Brazil', 'Panama', 'Pakistan', 'Burkina Faso',
       'Suriname', 'Virgin Islands', 'Togo', 'South Africa', 'Malawi',
       'Nigeria', 'Liberia', 'Vietnam', 'Costa Rica', 'Guam',
       'Myanmar (Burma)', 'Mali', 'Madagascar',
       'The Democratic Republic of the Congo', 'Cameroon', 'Georgia',
       'Puerto Rico', 'South Sudan', 'Moldova', 'Chile', 'Kyrgyzstan',
       'India', 'China', 'Bhutan'], dtype=object)
In [17]:
# Erstellen der Länderlist mit der Anzahl der fehlenden Regionen
mis_reg = df.loc[df['region'].isna(),'country'].value_counts()
In [18]:
mis_reg.head(36)
Out[18]:
country
El Salvador      20251
Kenya             8752
Rwanda            6138
United States     5173
Senegal           3231
Lebanon           1823
Turkey            1687
Kosovo            1419
Indonesia         1065
Iraq               993
Colombia           777
Mexico             706
Cameroon           692
Nicaragua          640
Benin              495
Madagascar         430
Albania            315
Uganda             211
Azerbaijan         170
Peru               160
Tanzania           127
Sierra Leone       119
Guatemala           99
Tajikistan          98
Bolivia             97
Palestine           89
Liberia             82
Philippines         81
Ghana               79
Honduras            71
Puerto Rico         68
Paraguay            62
Zimbabwe            57
Burundi             56
India               43
Brazil              41
Name: count, dtype: int64
In [19]:
mis_reg.tail(36)
Out[19]:
country
Ecuador                                 37
South Sudan                             36
Haiti                                   36
Zambia                                  34
Malawi                                  31
Jordan                                  29
Cambodia                                25
Samoa                                   24
Costa Rica                              18
Dominican Republic                      18
Mozambique                              15
Timor-Leste                             14
Israel                                  10
Togo                                     7
Burkina Faso                             6
Myanmar (Burma)                          6
Nigeria                                  6
Mali                                     5
Armenia                                  5
Pakistan                                 5
Yemen                                    5
Suriname                                 4
The Democratic Republic of the Congo     4
Mongolia                                 4
Vietnam                                  3
Virgin Islands                           2
Panama                                   2
South Africa                             2
Belize                                   2
Moldova                                  2
Kyrgyzstan                               1
China                                    1
Georgia                                  1
Chile                                    1
Guam                                     1
Bhutan                                   1
Name: count, dtype: int64
In [20]:
# Betrachtung von El Salvador
df.loc[df['country'].isin(['El Salvador']), 'region'].value_counts()
Out[20]:
region
San Miguel                                   2737
Gotera                                       2300
Usulután                                     2231
Ciudad El Triunfo                            2176
El Transito                                  1842
Osicala                                      1712
La Unión                                     1615
Sensuntepeque                                1194
Anamoros                                     1074
Ciudad Barrios                                982
Jiquilisco                                    707
San Vicente                                   675
San Miguel, San Miguel                         68
San Rafael de Oriente, San Miguel              35
San Francisco Gotera, Morazan                  30
Corinto, Morazan                               29
Zacatecoluca                                   26
Jiquilisco, Usulutan                           22
El Transito, San Miguel                        18
San Carlos, Morazan                            18
Jucuapa, Usulutan                              15
El Divisadero,  Morazan                        14
Guatajiagua, Morazan                           14
Lolotiquillo, Morazan                          10
La Libertad                                     9
Ahuachapan                                      9
San Jorge, San Miguel                           8
Concepcion Batres, Usulutan                     7
Chilanga, Morazan                               7
jocoaitique,Morazan                             4
Santa Ana                                       4
Osicala, Morazan                                3
Sonsonate                                       2
San Buena Ventura, Usulutan                     2
Meanguera, Morazan                              2
Yamabal, Morazan                                2
Chinameca, San Miguel                           2
Delicias de Concepcion, Morazan                 2
Cacaopera, Morazan                              2
Semsembra, Morazan                              2
Gualococti, Morazan                             2
San Isidro, Morazán                             1
La Libertad, La Libertad                        1
Chalatenango, Chalatenango                      1
San Simon Morazan.                              1
Berlin, Usulutan                                1
La Palma                                        1
Joateca, Morazán                                1
Moncagua, San Miguel.                           1
Yoloaiquin, Morazan                             1
Canton San Francisco, San Simon, Morazan.       1
Santiago de Maria, Usulutan                     1
Name: count, dtype: int64

Anhand des Falles mit dem Land in denen am meisten die Region fehlt, El Salvadore, zeigt sich das eine einfacher Zusammenhang zwischen country und region nicht besteht. Da wir nicht fein in die einzelnen Länder bei unserer Analyse reinschauen und die Region nicht einfach ermitteln können und diese erstmal nicht benötigen, können wir die NaN Einträge hier ignorieren.

Die Spalte region ist für unsere Analyse zu feingliedrig, da wir erstmal global betrachen. Sie kann für unsere Analyse erstmal gelöscht weren

In [21]:
# Löschen der Spalte region
df.drop(columns='region', inplace=True)
df
Out[21]:
funded_amount loan_amount activity sector country_code country currency term_in_months lender_count borrower_genders repayment_interval
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan PKR 12.0 12 female irregular
1 575.0 575.0 Rickshaw Transportation PK Pakistan PKR 11.0 14 female, female irregular
2 150.0 150.0 Transportation Transportation IN India INR 43.0 6 female bullet
3 200.0 200.0 Embroidery Arts PK Pakistan PKR 11.0 8 female irregular
4 400.0 400.0 Milk Sales Food PK Pakistan PKR 14.0 16 female monthly
... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay USD 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture KE Kenya KES 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment KE Kenya KES 13.0 0 NaN monthly
671203 0.0 25.0 Livestock Agriculture KE Kenya KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture KE Kenya KES 13.0 0 female monthly

671205 rows × 11 columns

Case borrower_genders¶

In [22]:
print("Anzahl fehlender Werte Gender:", df["borrower_genders"].isna().sum())
print(f"Prozent {df.borrower_genders.isna().sum() / df.size * 100: .4f}%")
Anzahl fehlender Werte Gender: 4221
Prozent  0.0572%
In [23]:
# Erstellen eines überlagernden Histogrames um besser auffälligkeiten bei der verteilung von NaN werten zu sehen
mask = df["borrower_genders"].isnull()
fig = go.Figure()
fig.add_trace(go.Histogram(x=df.loc[mask, "country"], name="Fehlende Gender"))
fig.add_trace(go.Histogram(x=df.loc[~mask, "country"],
                           name="Gender angegeben"))
fig.update_yaxes(type="log")
fig.update_layout(width=1000, height=800, barmode='stack')

In diesem Graph (Achtung Log10 Scala) ist zu erkennen das es keine große Häufung von Nullwerten bei borrower_gender in einem einzelnen Land gibt. Nominel sind Colombia, Kenya und El Salvadore am höchsten aber hier ist der Anteil der NaN Werte im vergleich zu den gegebenen Werten immernoch sehr gering.

Ersetze die NaN zu 'unknown' und behandle diese Einträge bei der Analyse von geschlechtspezifischen Faktoren entsprechend.

In [24]:
# Ersetzen der NaN durch den Eintrag unknown
df.loc[df["borrower_genders"].isna(), 'borrower_genders'] = 'unknown'
df["borrower_genders"].isna().sum()
Out[24]:
0
In [25]:
df
Out[25]:
funded_amount loan_amount activity sector country_code country currency term_in_months lender_count borrower_genders repayment_interval
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan PKR 12.0 12 female irregular
1 575.0 575.0 Rickshaw Transportation PK Pakistan PKR 11.0 14 female, female irregular
2 150.0 150.0 Transportation Transportation IN India INR 43.0 6 female bullet
3 200.0 200.0 Embroidery Arts PK Pakistan PKR 11.0 8 female irregular
4 400.0 400.0 Milk Sales Food PK Pakistan PKR 14.0 16 female monthly
... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay USD 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture KE Kenya KES 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment KE Kenya KES 13.0 0 unknown monthly
671203 0.0 25.0 Livestock Agriculture KE Kenya KES 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture KE Kenya KES 13.0 0 female monthly

671205 rows × 11 columns

Untersuchen von eventuellen Platzhaltern in den Daten¶

In [26]:
# Gibt es Auffälligkeiten in activity?
df["activity"].unique()
Out[26]:
array(['Fruits & Vegetables', 'Rickshaw', 'Transportation', 'Embroidery',
       'Milk Sales', 'Services', 'Dairy', 'Beauty Salon', 'Manufacturing',
       'Food Production/Sales', 'Wholesale', 'General Store',
       'Clothing Sales', 'Poultry', 'Tailoring', 'Sewing', 'Bakery',
       'Restaurant', 'Food Stall', 'Farming', 'Construction Supplies',
       'Personal Products Sales', 'Home Products Sales',
       'Natural Medicines', 'Fish Selling', 'Education provider',
       'Shoe Sales', 'Machinery Rental', 'Butcher Shop', 'Pigs',
       'Personal Expenses', 'Food Market', 'Cosmetics Sales',
       'Personal Housing Expenses', 'Retail', 'Energy', 'Grocery Store',
       'Construction', 'Agriculture', 'Motorcycle Transport',
       'Charcoal Sales', 'Food', 'Pharmacy', 'Fishing', 'Timber Sales',
       'Cattle', 'Electronics Repair', 'Electronics Sales', 'Vehicle',
       'Cafe', 'Blacksmith', 'Higher education costs', 'Used Clothing',
       'Fuel/Firewood', 'Upholstery', 'Catering', 'Animal Sales',
       'Cereals', 'Vehicle Repairs', 'Arts',
       'Cloth & Dressmaking Supplies', 'Mobile Phones', 'Spare Parts',
       'Clothing', 'Metal Shop', 'Barber Shop', 'Furniture Making',
       'Crafts', 'Home Energy', 'Home Appliances', 'Wedding Expenses',
       'Taxi', 'Secretarial Services', 'Livestock', 'Property',
       'Recycling', 'Farm Supplies', 'Auto Repair', 'Beverages',
       'Plastics Sales', 'Electrical Goods', 'Carpentry', 'Photography',
       'Jewelry', 'Bricks', 'Pub', 'Phone Use Sales',
       'Water Distribution', 'Paper Sales', 'Computers',
       'Liquor Store / Off-License', 'Utilities', 'Knitting', 'Weaving',
       'Party Supplies', 'Medical Clinic', 'Internet Cafe',
       'Consumer Goods', 'Cement', 'Electrician',
       'Primary/secondary school costs', 'Veterinary Sales',
       'Land Rental', 'Laundry', 'Call Center', 'Perfumes', 'Hotel',
       'Motorcycle Repair', 'Movie Tapes & DVDs', 'Quarrying',
       'Personal Medical Expenses', 'Bookstore', 'Decorations Sales',
       'Recycled Materials', 'Office Supplies', 'Souvenir Sales',
       'Renewable Energy Products', 'Health', 'Printing', 'Phone Repair',
       'Traveling Sales', 'Flowers', 'Bicycle Repair', 'Entertainment',
       'Phone Accessories', 'Hardware', 'Used Shoes',
       'Music Discs & Tapes', 'Games', 'Balut-Making', 'Textiles',
       'Child Care', 'Goods Distribution', 'Florist', 'Cobbler', 'Dental',
       'Bookbinding', 'Cheese Making', 'Bicycle Sales', 'Well digging',
       'Technology', 'Musical Performance', 'Waste Management', 'Film',
       'Tourism', 'Musical Instruments', 'Religious Articles',
       'Machine Shop', 'Cleaning Services', 'Sporting Good Sales',
       'Patchwork', 'Funerals', 'Air Conditioning', 'Communications',
       'Adult Care', 'Landscaping / Gardening', 'Aquaculture',
       'Beekeeping', 'Event Planning', 'Celebrations', 'Computer',
       'Personal Care Products', 'Mobile Transactions'], dtype=object)
In [27]:
# Gibt es Auffälligkeiten in sector?
df["sector"].unique()
Out[27]:
array(['Food', 'Transportation', 'Arts', 'Services', 'Agriculture',
       'Manufacturing', 'Wholesale', 'Retail', 'Clothing', 'Construction',
       'Health', 'Education', 'Personal Use', 'Housing', 'Entertainment'],
      dtype=object)
In [28]:
# Gibt es Auffälligkeiten in country?
df["country"].unique()
Out[28]:
array(['Pakistan', 'India', 'Kenya', 'Nicaragua', 'El Salvador',
       'Tanzania', 'Philippines', 'Peru', 'Senegal', 'Cambodia',
       'Liberia', 'Vietnam', 'Iraq', 'Honduras', 'Palestine', 'Mongolia',
       'United States', 'Mali', 'Colombia', 'Tajikistan', 'Guatemala',
       'Ecuador', 'Bolivia', 'Yemen', 'Ghana', 'Sierra Leone', 'Haiti',
       'Chile', 'Jordan', 'Uganda', 'Burundi', 'Burkina Faso',
       'Timor-Leste', 'Indonesia', 'Georgia', 'Ukraine', 'Kosovo',
       'Albania', 'The Democratic Republic of the Congo', 'Costa Rica',
       'Somalia', 'Zimbabwe', 'Cameroon', 'Turkey', 'Azerbaijan',
       'Dominican Republic', 'Brazil', 'Mexico', 'Kyrgyzstan', 'Armenia',
       'Paraguay', 'Lebanon', 'Samoa', 'Israel', 'Rwanda', 'Zambia',
       'Nepal', 'Congo', 'Mozambique', 'South Africa', 'Togo', 'Benin',
       'Belize', 'Suriname', 'Thailand', 'Nigeria', 'Mauritania',
       'Vanuatu', 'Panama', 'Virgin Islands',
       'Saint Vincent and the Grenadines',
       "Lao People's Democratic Republic", 'Malawi', 'Myanmar (Burma)',
       'Moldova', 'South Sudan', 'Solomon Islands', 'China', 'Egypt',
       'Guam', 'Afghanistan', 'Madagascar', 'Namibia', 'Puerto Rico',
       'Lesotho', "Cote D'Ivoire", 'Bhutan'], dtype=object)
In [29]:
# Gibt es Auffälligkeiten in repayment_interval?
df["repayment_interval"].unique()
Out[29]:
array(['irregular', 'bullet', 'monthly', 'weekly'], dtype=object)

In den Kategorischen Werten ausser borrower_genders sind keine Auffäligkeiten zu finden.

Keine Handlungen erforderlich

Löschen von weitern nicht benötigten Spalten¶

Die currency Spalte wird nicht von uns weiter für die Analyse benötigt und kann deshalb gelöscht werden

In [30]:
# Löschen der currency Spalte
df.drop(columns='currency', inplace=True)
df
Out[30]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count borrower_genders repayment_interval
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 female irregular
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 female, female irregular
2 150.0 150.0 Transportation Transportation IN India 43.0 6 female bullet
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 female irregular
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 female monthly
... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 female monthly
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 female monthly
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 unknown monthly
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly

671205 rows × 10 columns

Aufbereitung der Spalte borrower_genders¶

Die Spalte borrower_genders ist mit einer Liste der einzelnen beteiligten Projektteilnehmern befüllt. Dies führt zu vielen Permutationen. Nachfolgend werden diese in zwei neue Spalten aufgesplittet. Jeweils mit der Anzahl der Frauen und Männer. Wenn das Geschlecht unbekannt ist wird in beiden 0 eingetragen. Eine leichte verfälschung der Daten ist dabei möglich da bei negativen Fragen hier potenziell die Unbekannten mitgezählt werden könnten. Dies wird durch geschicktes Masking vermieden. Anschliesend wird die nicht mehr benötigte Spalte borrower_genders gelöscht.

In [31]:
df["borrower_genders"].unique()
Out[31]:
array(['female', 'female, female', 'female, female, female', ...,
       'female, female, male, female, female, female, female, female, female, female, male, male, female, female, male, female, female, female, female, female, female, female',
       'male, female, female, female, female, female, female, female, male, male, female, male, female, male, male, male',
       'female, female, female, male, female, female, female, male, female, female, female, male, female, male, female, female, female, female, female, female, female, female, female, female, female, female, female, female, male'],
      dtype=object)
In [32]:
from collections import Counter
# Erstellt performant ein dict mit den einzelnen counts für alle Elemente in borrower_genders.
# Der Algorytmus der Funktion ist gut optimiert und besser als die klassische for-Schleife
gender_dict = Counter(df["borrower_genders"].dropna())

f = 0  # Zähler für female
m = 0  # Zähler für male
new_gender_dict = {}  # Dict für die Ergebnisse

# Zählt die einzelnen instanzen von female und male durch und erstellt ein dict mit dem
# key = 'borrower_genders' und einer Liste mit Anzahl [female, male]
for key, val in gender_dict.items():
    temp_key = key.split(', ')
    for v in temp_key:
        if v == 'female':
            f += 1
        elif v == 'male':
            m += 1
    new_gender_dict[key] = [f, m]
    f = 0
    m = 0

# Neues Dict wird in ein Dataframe eingelesen
df_cg = pd.DataFrame.from_dict(new_gender_dict, orient='index').reindex()
df_cg

# Left Join mit der Originaltabelle in neue Arbeitstabelle
df_join_g = df.merge(df_cg,
                     how='left',
                     left_on='borrower_genders',
                     right_index=True)
df_join_g
Out[32]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count borrower_genders repayment_interval 0 1
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 female irregular 1 0
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 female, female irregular 2 0
2 150.0 150.0 Transportation Transportation IN India 43.0 6 female bullet 1 0
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 female irregular 1 0
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 female monthly 1 0
... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 female monthly 1 0
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 female monthly 1 0
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 unknown monthly 0 0
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly 1 0
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly 1 0

671205 rows × 12 columns

In [33]:
# Spaltennamen korrigieren
df_join_g.rename(mapper={0: 'female_nr', 1: 'male_nr'}, axis=1, inplace=True)
df_join_g
Out[33]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count borrower_genders repayment_interval female_nr male_nr
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 female irregular 1 0
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 female, female irregular 2 0
2 150.0 150.0 Transportation Transportation IN India 43.0 6 female bullet 1 0
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 female irregular 1 0
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 female monthly 1 0
... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 female monthly 1 0
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 female monthly 1 0
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 unknown monthly 0 0
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly 1 0
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 female monthly 1 0

671205 rows × 12 columns

In [34]:
# borrower_genders nicht weiter notwendig für diese Tabelle da sie nun neu Kodiert ist
df_join_g.drop(columns='borrower_genders', inplace=True)
df_join_g
Out[34]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count repayment_interval female_nr male_nr
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 irregular 1 0
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 irregular 2 0
2 150.0 150.0 Transportation Transportation IN India 43.0 6 bullet 1 0
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 irregular 1 0
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 monthly 1 0
... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 monthly 1 0
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 monthly 1 0
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 monthly 0 0
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0

671205 rows × 11 columns

In [35]:
# Überprüfen ob noch NaN Werte vorhanden sind
df_join_g.isna().sum()
Out[35]:
funded_amount         0
loan_amount           0
activity              0
sector                0
country_code          0
country               0
term_in_months        0
lender_count          0
repayment_interval    0
female_nr             0
male_nr               0
dtype: int64

Testen ob funded_amount und lender_count logisch passen ist¶

In [36]:
# Logischer Verglich mir XOR
df.loc[(df["funded_amount"] == 0) ^ (df["lender_count"] == 0)]
Out[36]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count borrower_genders repayment_interval

Es gibt keine Zeile in der nur funded_amount = 0 ohne das auch lender_count = 0 ist und visa versa

Keine Handlung ist notwendig

EDA Frage: Was für einen Einfluss hat das Geschlecht unserer Antragsteller?¶

Univariate Analyse: Wie ist die Verteilung der Geschlechter in Kategorien?¶

Zur weiteren Analyse kategorisieren wir die ehemalige borrower_genders weiter.

  • Einzelperson Man
  • Einzelperson Frau
  • Unbekannt
  • Kleine Gruppe (2-4) nur Männer
  • Kleine Gruppe (2-4) nur Frauen
  • Kleine Gruppe (2-4) gemischt
  • Mittlere Gruppe (5-8) nur Männer
  • Mittlere Gruppe (5-8) nur Frauen
  • Mittlere Gruppe (5-8) gemischt
  • Große Gruppe (9+) nur Männer
  • Große Gruppe (9+) nur Frauen
  • Große Gruppe (9+) gemischt

Hypothese: Diese Aufteilung wird gewählt um so vergleichbarere Kundenkategorien zu erzeugen

In [37]:
#Arbeitskopie erstellen
df_a = df_join_g.copy()
In [38]:
df_a
Out[38]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count repayment_interval female_nr male_nr
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 irregular 1 0
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 irregular 2 0
2 150.0 150.0 Transportation Transportation IN India 43.0 6 bullet 1 0
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 irregular 1 0
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 monthly 1 0
... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 monthly 1 0
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 monthly 1 0
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 monthly 0 0
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0

671205 rows × 11 columns

In [39]:
# Summieren von Mann und Frau um die Größe der Gruppe zu bestimmen
df_a['group_size'] = df_a["female_nr"] + df_a["male_nr"]
df_a
Out[39]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count repayment_interval female_nr male_nr group_size
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 irregular 1 0 1
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 irregular 2 0 2
2 150.0 150.0 Transportation Transportation IN India 43.0 6 bullet 1 0 1
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 irregular 1 0 1
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 monthly 1 0 1
... ... ... ... ... ... ... ... ... ... ... ... ...
671200 0.0 25.0 Livestock Agriculture PY Paraguay 13.0 0 monthly 1 0 1
671201 25.0 25.0 Livestock Agriculture KE Kenya 13.0 1 monthly 1 0 1
671202 0.0 25.0 Games Entertainment KE Kenya 13.0 0 monthly 0 0 0
671203 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0 1
671204 0.0 25.0 Livestock Agriculture KE Kenya 13.0 0 monthly 1 0 1

671205 rows × 12 columns

In [40]:
# Überprüfen ob Gruppengröße schlüssig ist
df_a['group_size'].describe()
Out[40]:
count    671205.000000
mean          2.005664
std           3.406619
min           0.000000
25%           1.000000
50%           1.000000
75%           1.000000
max          50.000000
Name: group_size, dtype: float64

Es sind keine auffälligen Extremwerte, die nicht im Rahmen des Geschäftsmodelles liegen würden, zu sehen. Die 0 Werte stellen unbekannte Gruppen dar.

Keine Handlungen wegen zu großen oder kleinen Gruppen notwendig

In [41]:
# Erstellen der Filtermasken für die Gruppen
mask1f = (df_a['female_nr'] == 1) & (df_a['male_nr'] == 0) & (df_a['group_size'].between(1, 1))
mask1m = (df_a['female_nr'] == 0) & (df_a['male_nr'] == 1) & (df_a['group_size'].between(1, 1))
mask1u = (df_a['female_nr'] == 0) & (df_a['male_nr'] == 0) & (df_a['group_size'].between(0, 0))

mask2f = (df_a['female_nr'].between(2, 4)) & (df_a['male_nr'].between(0, 0)) & (df_a['group_size'].between(2, 4))
mask2m = (df_a['female_nr'].between(0, 0)) & (df_a['male_nr'].between(2, 4)) & (df_a['group_size'].between(2, 4))
mask2g = (df_a['female_nr'].between(1, 3)) & (df_a['male_nr'].between(1, 3)) & (df_a['group_size'].between(2, 4))

mask3f = (df_a['female_nr'].between(5, 8)) & (df_a['male_nr'].between(0, 0)) & (df_a['group_size'].between(5, 8))
mask3m = (df_a['female_nr'].between(0, 0)) & (df_a['male_nr'].between(5, 8)) & (df_a['group_size'].between(5, 8))
mask3g = (df_a['female_nr'].between(1, 7)) & (df_a['male_nr'].between(1, 7)) & (df_a['group_size'].between(5, 8))

mask4f = (df_a['female_nr'] > 9) & (df_a['male_nr'] == 0) & (df_a['group_size'] > 9)
mask4m = (df_a['female_nr'] == 0) & (df_a['male_nr'] > 9) & (df_a['group_size'] > 9)
mask4g = (df_a['female_nr'] > 1) & (df_a['male_nr'] > 1) & (df_a['group_size'] > 9)
In [42]:
print('Einzelperson Man', mask1m.sum())
print('Einzelperson Frau', mask1f.sum())
print('Unbekannt', mask1u.sum())
print('Kleine Gruppe (2-4) nur Männer', mask2m.sum())
print('Kleine Gruppe (2-4) nur Frauen', mask2f.sum())
print('Kleine Gruppe (2-4) gemischt', mask2g.sum())
print('Mittlere Gruppe (5-8) nur Männer', mask3m.sum())
print('Mittlere Gruppe (5-8) nur Frauen', mask3f.sum())
print('Mittlere Gruppe (5-8) gemischt', mask3g.sum())
print('Große Gruppe (9+) nur Männer', mask4m.sum())
print('Große Gruppe (9+) nur Frauen', mask4f.sum())
print('Große Gruppe (9+) gemischt', mask4g.sum())
Einzelperson Man 134710
Einzelperson Frau 426502
Unbekannt 4221
Kleine Gruppe (2-4) nur Männer 2315
Kleine Gruppe (2-4) nur Frauen 32892
Kleine Gruppe (2-4) gemischt 10752
Mittlere Gruppe (5-8) nur Männer 1261
Mittlere Gruppe (5-8) nur Frauen 14305
Mittlere Gruppe (5-8) gemischt 12374
Große Gruppe (9+) nur Männer 130
Große Gruppe (9+) nur Frauen 13175
Große Gruppe (9+) gemischt 12991
In [43]:
# Einfügen der Gruppen in eine neue Spalte
df_a.loc[mask1m, 'group_class'] = 'Einzelperson Man'
df_a.loc[mask1f, 'group_class'] = 'Einzelperson Frau'
df_a.loc[mask1u, 'group_class'] = 'Unbekannt'

df_a.loc[mask2m, 'group_class'] = 'Kleine Gruppe (2-4) nur Männer'
df_a.loc[mask2f, 'group_class'] = 'Kleine Gruppe (2-4) nur Frauen'
df_a.loc[mask2g, 'group_class'] = 'Kleine Gruppe (2-4) gemischt'

df_a.loc[mask3m, 'group_class'] = 'Mittlere Gruppe (5-8) nur Männer'
df_a.loc[mask3f, 'group_class'] = 'Mittlere Gruppe (5-8) nur Frauen'
df_a.loc[mask3g, 'group_class'] = 'Mittlere Gruppe (5-8) gemischt'

df_a.loc[mask4m, 'group_class'] = 'Große Gruppe (9+) nur Männer'
df_a.loc[mask4f, 'group_class'] = 'Große Gruppe (9+) nur Frauen'
df_a.loc[mask4g, 'group_class'] = 'Große Gruppe (9+) gemischt'

df_a['group_class'].value_counts()
Out[43]:
group_class
Einzelperson Frau                   426502
Einzelperson Man                    134710
Kleine Gruppe (2-4) nur Frauen       32892
Mittlere Gruppe (5-8) nur Frauen     14305
Große Gruppe (9+) nur Frauen         13175
Große Gruppe (9+) gemischt           12991
Mittlere Gruppe (5-8) gemischt       12374
Kleine Gruppe (2-4) gemischt         10752
Unbekannt                             4221
Kleine Gruppe (2-4) nur Männer        2315
Mittlere Gruppe (5-8) nur Männer      1261
Große Gruppe (9+) nur Männer           130
Name: count, dtype: int64
In [44]:
df_a.head(10)
Out[44]:
funded_amount loan_amount activity sector country_code country term_in_months lender_count repayment_interval female_nr male_nr group_size group_class
0 300.0 300.0 Fruits & Vegetables Food PK Pakistan 12.0 12 irregular 1 0 1 Einzelperson Frau
1 575.0 575.0 Rickshaw Transportation PK Pakistan 11.0 14 irregular 2 0 2 Kleine Gruppe (2-4) nur Frauen
2 150.0 150.0 Transportation Transportation IN India 43.0 6 bullet 1 0 1 Einzelperson Frau
3 200.0 200.0 Embroidery Arts PK Pakistan 11.0 8 irregular 1 0 1 Einzelperson Frau
4 400.0 400.0 Milk Sales Food PK Pakistan 14.0 16 monthly 1 0 1 Einzelperson Frau
5 250.0 250.0 Services Services KE Kenya 4.0 6 irregular 1 0 1 Einzelperson Frau
6 200.0 200.0 Dairy Agriculture IN India 43.0 8 bullet 1 0 1 Einzelperson Frau
7 400.0 400.0 Beauty Salon Services PK Pakistan 14.0 8 monthly 1 0 1 Einzelperson Frau
8 475.0 475.0 Manufacturing Manufacturing PK Pakistan 14.0 19 monthly 1 0 1 Einzelperson Frau
9 625.0 625.0 Food Production/Sales Food PK Pakistan 11.0 24 irregular 1 0 1 Einzelperson Frau
In [45]:
# Das selbe nochmal um die Obergruppen einzupflegen um diese besser grafisch darstellen zu können
df_a.loc[mask1m, 'group_gender'] = 'nur Männer'
df_a.loc[mask1f, 'group_gender'] = 'nur Frauen'
df_a.loc[mask1u, 'group_gender'] = 'unbekannt'

df_a.loc[mask2m, 'group_gender'] = 'nur Männer'
df_a.loc[mask2f, 'group_gender'] = 'nur Frauen'
df_a.loc[mask2g, 'group_gender'] = 'gemischt'

df_a.loc[mask3m, 'group_gender'] = 'nur Männer'
df_a.loc[mask3f, 'group_gender'] = 'nur Frauen'
df_a.loc[mask3g, 'group_gender'] = 'gemischt'

df_a.loc[mask4m, 'group_gender'] = 'nur Männer'
df_a.loc[mask4f, 'group_gender'] = 'nur Frauen'
df_a.loc[mask4g, 'group_gender'] = 'gemischt'

df_a['group_gender'].value_counts()
Out[45]:
group_gender
nur Frauen    486874
nur Männer    138416
gemischt       36117
unbekannt       4221
Name: count, dtype: int64
In [46]:
# Grouping nach Summe pro Kundenkategorie
df_g = df_a.groupby(by=['group_class', 'group_gender'],
                    as_index=False).agg(count_group=('group_class', 'count'))
df_g
Out[46]:
group_class group_gender count_group
0 Einzelperson Frau nur Frauen 426502
1 Einzelperson Man nur Männer 134710
2 Große Gruppe (9+) gemischt gemischt 12991
3 Große Gruppe (9+) nur Frauen nur Frauen 13175
4 Große Gruppe (9+) nur Männer nur Männer 130
5 Kleine Gruppe (2-4) gemischt gemischt 10752
6 Kleine Gruppe (2-4) nur Frauen nur Frauen 32892
7 Kleine Gruppe (2-4) nur Männer nur Männer 2315
8 Mittlere Gruppe (5-8) gemischt gemischt 12374
9 Mittlere Gruppe (5-8) nur Frauen nur Frauen 14305
10 Mittlere Gruppe (5-8) nur Männer nur Männer 1261
11 Unbekannt unbekannt 4221
In [47]:
# Ausrechen des Prozentanteils der jeweiligen Kundenkategorien
df_g['prozent'] = round(df_g['count_group'] / df_g['count_group'].sum() * 100, 2)

# Einfügen eines % Zeichen für eine spätere bessere Darstellung
df_g = df_g.astype({'prozent': 'str'})
df_g['prozent'] = df_g['prozent'] + '%'
df_g
Out[47]:
group_class group_gender count_group prozent
0 Einzelperson Frau nur Frauen 426502 64.08%
1 Einzelperson Man nur Männer 134710 20.24%
2 Große Gruppe (9+) gemischt gemischt 12991 1.95%
3 Große Gruppe (9+) nur Frauen nur Frauen 13175 1.98%
4 Große Gruppe (9+) nur Männer nur Männer 130 0.02%
5 Kleine Gruppe (2-4) gemischt gemischt 10752 1.62%
6 Kleine Gruppe (2-4) nur Frauen nur Frauen 32892 4.94%
7 Kleine Gruppe (2-4) nur Männer nur Männer 2315 0.35%
8 Mittlere Gruppe (5-8) gemischt gemischt 12374 1.86%
9 Mittlere Gruppe (5-8) nur Frauen nur Frauen 14305 2.15%
10 Mittlere Gruppe (5-8) nur Männer nur Männer 1261 0.19%
11 Unbekannt unbekannt 4221 0.63%

Plot 1 zum bewerten¶

In [48]:
# Manuelle Reinfolge der x-Achse vordefinieren, da Plotly Express keine gute Reinfolge hinbekommt
order = [
    'Einzelperson Frau', 'Einzelperson Man', 'Kleine Gruppe (2-4) nur Frauen',
    'Kleine Gruppe (2-4) nur Männer', 'Kleine Gruppe (2-4) gemischt',
    'Mittlere Gruppe (5-8) nur Frauen', 'Mittlere Gruppe (5-8) nur Männer',
    'Mittlere Gruppe (5-8) gemischt', 'Große Gruppe (9+) nur Frauen',
    'Große Gruppe (9+) nur Männer', 'Große Gruppe (9+) gemischt', 'Unbekannt'
]

fig_u1 = px.bar(
    df_g,
    x='group_class',
    y='count_group',
    color='group_gender', # Kodierung der Gendergruppen über Farben
    color_discrete_map={
        'nur Frauen': '#fc0377',
        'nur Männer': '#0362fc',
        'gemischt': '#ce03fc',
        'unbekannt': '#27c71c'
    },
    labels={
        'group_class': 'Gruppenaufteilung',
        'count_group': 'Anzahl Debitoren (in log10)',
        'group_gender': 'Zusammensetzung'
    },
    height=600,
    title=
    "Auflistung der Projekte nach Gruppengröße der Antragsteller und geschlechtlicher Zusammensetzung",
    text='prozent')

# y-Achse soll Log10 sein
fig_u1.update_yaxes(type="log")

# x-Achse Manuell Reinfolge festlegen
fig_u1.update_xaxes(categoryorder="array")
fig_u1.update_xaxes(categoryarray=order)

# Hilfslinien Zeichen für eine Bessere Darstellung der Kundenkategorien
fig_u1.add_vline(x=1.5)
fig_u1.add_vline(x=4.5)
fig_u1.add_vline(x=7.5)
fig_u1.add_vline(x=10.5)

# Annotationen für eine Bessere Darstellung der Kundenkategorien
fig_u1.add_annotation(x=0.5,
                      y=5.8,
                      text="Einzelpersonen",
                      font=dict(size=14),
                      showarrow=False,
                      yshift=0)
fig_u1.add_annotation(x=3,
                      y=5.8,
                      text="Gruppengröße 2-4",
                      font=dict(size=16),
                      showarrow=False,
                      yshift=0)
fig_u1.add_annotation(x=6,
                      y=5.8,
                      text="Gruppengröße 5-8",
                      font=dict(size=16),
                      showarrow=False,
                      yshift=0)
fig_u1.add_annotation(x=9,
                      y=5.8,
                      text="Gruppengröße 9+",
                      font=dict(size=16),
                      showarrow=False,
                      yshift=0)

# Um Clutter zu vermeiden keine Tick Beschriftung auf der x-Achse 
fig_u1.update_xaxes(showticklabels=False)

# Graph anzeigen
fig_u1.show()

Bitte die logarytmische Skala der y-Achse beachten bei der interpretation der Daten.

Der obrige Graph zeigt eindeutig die große dominanz von Anträgen von Frauen.

Selbst in den Fällen in denen mehrere Personen einen Antrag stellen sind reine Männergruppen deutlich unterrepresentiert. Insbesondere scheind es zu sein das größere Gruppen die ausschlieslich männlich sind eine Ausnahme darstellen.

Es wäre interessant weiter zu schauen ob es einen sichtbaren Unterschied zwischen weiblichen, mänlichen und gemischen Antragstellern gibt hinsichtlich der Funding Erfolgsquote.

Zudem zeigt der Graph das die Wahl der Kundenkategorien sinnvoll ist, da die Größenordnungen gut vergleichbar sind.

Hinweis: Eine nach Länderauswahl aufgeschlüsselte Ansicht befindet sich in der Dash App.

Bivariate Analyse: Wirkt sich das Geschlecht und die Gruppengröße auf die Fundingrate aus?¶

In [49]:
# Groupieren nach Kundenkategorien. Hier auch mit berücksichtigung des Fundings
df_g2 = df_a.groupby(by=['group_gender', 'group_class'], as_index=False).agg(
                                                         sum_loans=('loan_amount', 'sum'),
                                                         sum_funding=('funded_amount', 'sum'),
                                                         count=pd.NamedAgg(column='loan_amount', aggfunc='count'))
df_g2
Out[49]:
group_gender group_class sum_loans sum_funding count
0 gemischt Große Gruppe (9+) gemischt 33109550.0 31717075.0 12991
1 gemischt Kleine Gruppe (2-4) gemischt 8435750.0 7792700.0 10752
2 gemischt Mittlere Gruppe (5-8) gemischt 22959250.0 21760200.0 12374
3 nur Frauen Einzelperson Frau 252955025.0 239411095.0 426502
4 nur Frauen Große Gruppe (9+) nur Frauen 43952500.0 43261950.0 13175
5 nur Frauen Kleine Gruppe (2-4) nur Frauen 30407650.0 29089600.0 32892
6 nur Frauen Mittlere Gruppe (5-8) nur Frauen 25686875.0 24703950.0 14305
7 nur Männer Einzelperson Man 121109550.0 105472690.0 134710
8 nur Männer Große Gruppe (9+) nur Männer 320925.0 266525.0 130
9 nur Männer Kleine Gruppe (2-4) nur Männer 2702225.0 2330175.0 2315
10 nur Männer Mittlere Gruppe (5-8) nur Männer 2460550.0 2089225.0 1261
11 unbekannt Unbekannt 4954000.0 3896105.0 4221
In [50]:
# Berechnen der Fundingerfogsquote und Sortierung nach bestem Wert
df_g2['fundingrate'] = round(df_g2['sum_funding']/df_g2['sum_loans'] * 100, 2).astype('float')
df_g2.sort_values('fundingrate', axis=0, ascending=False, inplace=True)
df_g2
Out[50]:
group_gender group_class sum_loans sum_funding count fundingrate
4 nur Frauen Große Gruppe (9+) nur Frauen 43952500.0 43261950.0 13175 98.43
6 nur Frauen Mittlere Gruppe (5-8) nur Frauen 25686875.0 24703950.0 14305 96.17
0 gemischt Große Gruppe (9+) gemischt 33109550.0 31717075.0 12991 95.79
5 nur Frauen Kleine Gruppe (2-4) nur Frauen 30407650.0 29089600.0 32892 95.67
2 gemischt Mittlere Gruppe (5-8) gemischt 22959250.0 21760200.0 12374 94.78
3 nur Frauen Einzelperson Frau 252955025.0 239411095.0 426502 94.65
1 gemischt Kleine Gruppe (2-4) gemischt 8435750.0 7792700.0 10752 92.38
7 nur Männer Einzelperson Man 121109550.0 105472690.0 134710 87.09
9 nur Männer Kleine Gruppe (2-4) nur Männer 2702225.0 2330175.0 2315 86.23
10 nur Männer Mittlere Gruppe (5-8) nur Männer 2460550.0 2089225.0 1261 84.91
8 nur Männer Große Gruppe (9+) nur Männer 320925.0 266525.0 130 83.05
11 unbekannt Unbekannt 4954000.0 3896105.0 4221 78.65
In [51]:
# Nochmal die Prozente an der Gesamtpopulation berechnen um sie nacher in den Graphen als zusätzliche Info darzustellen
df_g2['prozent'] = round(df_g2['count'] / df_g2['count'].sum() * 100, 2)
df_g2 = df_g2.astype({'prozent':'str'})
df_g2['prozent'] = df_g2['prozent'] + '%'
df_g2
Out[51]:
group_gender group_class sum_loans sum_funding count fundingrate prozent
4 nur Frauen Große Gruppe (9+) nur Frauen 43952500.0 43261950.0 13175 98.43 1.98%
6 nur Frauen Mittlere Gruppe (5-8) nur Frauen 25686875.0 24703950.0 14305 96.17 2.15%
0 gemischt Große Gruppe (9+) gemischt 33109550.0 31717075.0 12991 95.79 1.95%
5 nur Frauen Kleine Gruppe (2-4) nur Frauen 30407650.0 29089600.0 32892 95.67 4.94%
2 gemischt Mittlere Gruppe (5-8) gemischt 22959250.0 21760200.0 12374 94.78 1.86%
3 nur Frauen Einzelperson Frau 252955025.0 239411095.0 426502 94.65 64.08%
1 gemischt Kleine Gruppe (2-4) gemischt 8435750.0 7792700.0 10752 92.38 1.62%
7 nur Männer Einzelperson Man 121109550.0 105472690.0 134710 87.09 20.24%
9 nur Männer Kleine Gruppe (2-4) nur Männer 2702225.0 2330175.0 2315 86.23 0.35%
10 nur Männer Mittlere Gruppe (5-8) nur Männer 2460550.0 2089225.0 1261 84.91 0.19%
8 nur Männer Große Gruppe (9+) nur Männer 320925.0 266525.0 130 83.05 0.02%
11 unbekannt Unbekannt 4954000.0 3896105.0 4221 78.65 0.63%
In [52]:
# Aufbereiten der Daten zu Listen um eine Konvertierungswarnung im nachfolgenden Plot zu umgehen und um leichter zu itterieren
fundinglist = df_g2['fundingrate'].to_list()
classlist = df_g2['group_class'].to_list()
genderlist = df_g2['group_gender'].to_list()
prozentlist = df_g2['prozent'].to_list()

Plot 2 zum bewerten¶

In [53]:
# Da Plotly Express keine Bulletpoints kann, wird auf die low-Level funktionalität zurückgegriffen
import plotly.graph_objects as go

fig_b1 = go.Figure()

# Erstellen der 12 Einzelnen Bulletpoints in einer for Schleife 
for x in range(0,12):
    # Berechnen von Layout Parametern
    y1 = (x*2)/25 + 0.08
    y2 = (x*2 + 1)/25 + 0.08
    
    # Ermitteln der Farbe für den Balken
    if genderlist[x] == 'nur Frauen':
        c = '#fc0377'
    elif genderlist[x] == 'nur Männer':
        c = '#0362fc'
    elif genderlist[x] == 'gemischt':
        c = '#ce03fc'
    else:
        c = '#27c71c'
    
    # Erstellen des individualisierten Einzelplotes als trace. Listen werden hier verwendet da Panda DataFrames nicht 
    # vollständig kompatibel sind.
    fig_b1.add_trace(go.Indicator(
        mode = "number+gauge", value = fundinglist[x],
        domain = {'x': [0.35, 1], 'y': [y1, y2]},
        title = {'text': classlist[x] + ' (' + prozentlist[x] + ')',  'font': {"size": 13}},
        gauge = {
            'shape': "bullet",
            'axis': {'range': [75, 100]},
            'steps': [
                {'range': [75, 80], 'color': "dimgray"},
                {'range': [80, 85], 'color': "grey"},
                {'range': [85, 90], 'color': "silver"},
                {'range': [90, 95], 'color': "lightgray"},
                {'range': [95, 100], 'color':'whitesmoke'}],
            'bar': {'color': c}}))

# Parameter für den Gesamtplot     
fig_b1.update_layout(height = 800 , 
                     margin = {'t':40, 'b':0, 'l':0}, 
                     title = 'Bulletchart: Fundingquote in Prozent aufgeteilt nach Gruppengröße und Geschlechteraufteilung')

# Darstellen des zusammengesetzten Plots
fig_b1.show()

Betrachtet wird die Fundingquote. Diese beinhaltet auch den Fall das nicht die komplette Kreditsumme beim Funding erziehlt wurde anteilig je nach erzieltem Teilbetrag.

Anhand des obrigen Bulletgraphen läst sich deutlich erkennen das wenn Männer ein Funding beantragen sie deutlich schlechtere Chanchen haben als Frauen oder gemischte Teams. Es zeigt sich sogar der Trent das je größer die reine Männergruppe ist, desto schlechter wird die Fundingquote.

Für Frauen und gemischten Gruppen ist das Gegenteil der Fall. Diese haben eine deutlich bessere Fundingquote. Tendenziel je größer die Gruppe desto höher ist diese Quote.

Wie schon oben erwähnt, stellen die Zahlen nicht den Anteil an erfolgreichen oder teilerfolgreichen Fundings dar. Diese könnten sich leicht unterscheiden.

Es ist zu untersuchen ob sich diese golbalen Werte auch in den einzelnen Ländern wiederfinden.

Multivariante Analyse: Wie verteilen sich die Gruppen nach den Herkunftsländern. Gibt es Unterschiede? Wie sieht der Fundingerfolg aus?¶

In [54]:
# Gruppieren nach Kundenkategorien und Ländern + Kpi's
df_g3 = df_a.groupby(by = ['group_gender', 'group_class', 'country'], as_index=False).agg(sum_loans=('loan_amount', 'sum'), 
                                                       sum_funding=('funded_amount', 'sum'),
                                                       mean_funding=('funded_amount', 'mean'),
                                                       median_funding=('funded_amount', 'median'),                                   
                                                       count = pd.NamedAgg(column='loan_amount', aggfunc='count'))
df_g3
Out[54]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count
0 gemischt Große Gruppe (9+) gemischt Benin 9725.0 9725.0 3241.666667 3500.0 3
1 gemischt Große Gruppe (9+) gemischt Bolivia 269100.0 251675.0 4934.803922 5200.0 51
2 gemischt Große Gruppe (9+) gemischt Burkina Faso 96775.0 96425.0 1506.640625 1200.0 64
3 gemischt Große Gruppe (9+) gemischt Burundi 2156725.0 2062650.0 2925.744681 2775.0 705
4 gemischt Große Gruppe (9+) gemischt Cambodia 1100.0 1100.0 366.666667 375.0 3
... ... ... ... ... ... ... ... ...
532 unbekannt Unbekannt United States 716300.0 481990.0 3012.437500 2750.0 160
533 unbekannt Unbekannt Vietnam 775.0 775.0 387.500000 387.5 2
534 unbekannt Unbekannt Yemen 12125.0 12125.0 2425.000000 750.0 5
535 unbekannt Unbekannt Zambia 38325.0 28700.0 844.117647 787.5 34
536 unbekannt Unbekannt Zimbabwe 46825.0 45050.0 804.464286 500.0 56

537 rows × 8 columns

In [55]:
# Kpi Fundingrate berechen
df_g3['fundingrate'] = round(df_g3['sum_funding'] / df_g3['sum_loans'] * 100, 2).astype('float')

df_g3
Out[55]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count fundingrate
0 gemischt Große Gruppe (9+) gemischt Benin 9725.0 9725.0 3241.666667 3500.0 3 100.00
1 gemischt Große Gruppe (9+) gemischt Bolivia 269100.0 251675.0 4934.803922 5200.0 51 93.52
2 gemischt Große Gruppe (9+) gemischt Burkina Faso 96775.0 96425.0 1506.640625 1200.0 64 99.64
3 gemischt Große Gruppe (9+) gemischt Burundi 2156725.0 2062650.0 2925.744681 2775.0 705 95.64
4 gemischt Große Gruppe (9+) gemischt Cambodia 1100.0 1100.0 366.666667 375.0 3 100.00
... ... ... ... ... ... ... ... ... ...
532 unbekannt Unbekannt United States 716300.0 481990.0 3012.437500 2750.0 160 67.29
533 unbekannt Unbekannt Vietnam 775.0 775.0 387.500000 387.5 2 100.00
534 unbekannt Unbekannt Yemen 12125.0 12125.0 2425.000000 750.0 5 100.00
535 unbekannt Unbekannt Zambia 38325.0 28700.0 844.117647 787.5 34 74.89
536 unbekannt Unbekannt Zimbabwe 46825.0 45050.0 804.464286 500.0 56 96.21

537 rows × 9 columns

In [56]:
# Prozent von der Gesamtpopulation berechnen
df_g3['prozent'] = round(df_g3['count'] / df_g3['count'].sum() * 100, 4)
In [57]:
df_g3
Out[57]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count fundingrate prozent
0 gemischt Große Gruppe (9+) gemischt Benin 9725.0 9725.0 3241.666667 3500.0 3 100.00 0.0005
1 gemischt Große Gruppe (9+) gemischt Bolivia 269100.0 251675.0 4934.803922 5200.0 51 93.52 0.0077
2 gemischt Große Gruppe (9+) gemischt Burkina Faso 96775.0 96425.0 1506.640625 1200.0 64 99.64 0.0096
3 gemischt Große Gruppe (9+) gemischt Burundi 2156725.0 2062650.0 2925.744681 2775.0 705 95.64 0.1059
4 gemischt Große Gruppe (9+) gemischt Cambodia 1100.0 1100.0 366.666667 375.0 3 100.00 0.0005
... ... ... ... ... ... ... ... ... ... ...
532 unbekannt Unbekannt United States 716300.0 481990.0 3012.437500 2750.0 160 67.29 0.0240
533 unbekannt Unbekannt Vietnam 775.0 775.0 387.500000 387.5 2 100.00 0.0003
534 unbekannt Unbekannt Yemen 12125.0 12125.0 2425.000000 750.0 5 100.00 0.0008
535 unbekannt Unbekannt Zambia 38325.0 28700.0 844.117647 787.5 34 74.89 0.0051
536 unbekannt Unbekannt Zimbabwe 46825.0 45050.0 804.464286 500.0 56 96.21 0.0084

537 rows × 10 columns

In [58]:
# Einrichten einer künstlichen size Skala um Unterschiede besser hervor zu heben
df_g3['p_size'] = 1000**(df_g3['fundingrate'] / 100)
df_g3
Out[58]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count fundingrate prozent p_size
0 gemischt Große Gruppe (9+) gemischt Benin 9725.0 9725.0 3241.666667 3500.0 3 100.00 0.0005 1000.000000
1 gemischt Große Gruppe (9+) gemischt Bolivia 269100.0 251675.0 4934.803922 5200.0 51 93.52 0.0077 639.145889
2 gemischt Große Gruppe (9+) gemischt Burkina Faso 96775.0 96425.0 1506.640625 1200.0 64 99.64 0.0096 975.438740
3 gemischt Große Gruppe (9+) gemischt Burundi 2156725.0 2062650.0 2925.744681 2775.0 705 95.64 0.1059 739.945954
4 gemischt Große Gruppe (9+) gemischt Cambodia 1100.0 1100.0 366.666667 375.0 3 100.00 0.0005 1000.000000
... ... ... ... ... ... ... ... ... ... ... ...
532 unbekannt Unbekannt United States 716300.0 481990.0 3012.437500 2750.0 160 67.29 0.0240 104.399880
533 unbekannt Unbekannt Vietnam 775.0 775.0 387.500000 387.5 2 100.00 0.0003 1000.000000
534 unbekannt Unbekannt Yemen 12125.0 12125.0 2425.000000 750.0 5 100.00 0.0008 1000.000000
535 unbekannt Unbekannt Zambia 38325.0 28700.0 844.117647 787.5 34 74.89 0.0051 176.481831
536 unbekannt Unbekannt Zimbabwe 46825.0 45050.0 804.464286 500.0 56 96.21 0.0084 769.661920

537 rows × 11 columns

In [59]:
# Erstellen einer neuen temp Sortierspallte um das Animation Framework besser zu machen
df_g3.loc[df_g3['group_class'] == 'Einzelperson Frau', 'sorting'] = 1
df_g3.loc[df_g3['group_class'] == 'Einzelperson Man', 'sorting'] = 2
df_g3.loc[df_g3['group_class'] == 'Kleine Gruppe (2-4) nur Frauen', 'sorting'] = 3
df_g3.loc[df_g3['group_class'] == 'Kleine Gruppe (2-4) nur Männer', 'sorting'] = 4
df_g3.loc[df_g3['group_class'] == 'Kleine Gruppe (2-4) gemischt', 'sorting'] = 5
df_g3.loc[df_g3['group_class'] == 'Mittlere Gruppe (5-8) nur Frauen', 'sorting'] = 6
df_g3.loc[df_g3['group_class'] == 'Mittlere Gruppe (5-8) nur Männer', 'sorting'] = 7
df_g3.loc[df_g3['group_class'] == 'Mittlere Gruppe (5-8) gemischt', 'sorting'] = 8
df_g3.loc[df_g3['group_class'] == 'Große Gruppe (9+) nur Frauen', 'sorting'] = 9
df_g3.loc[df_g3['group_class'] == 'Große Gruppe (9+) nur Männer', 'sorting'] = 10
df_g3.loc[df_g3['group_class'] == 'Große Gruppe (9+) gemischt', 'sorting'] = 11
df_g3.loc[df_g3['group_class'] == 'Unbekannt', 'sorting'] = 12
In [60]:
# Klassifizierung für Symbole
df_g3.loc[df_g3["count"] <= 10, 'count group'] = 'F-Tier 1-10'
df_g3.loc[df_g3["count"].between(11,50), 'count group'] = 'D-Tier 11-50'
df_g3.loc[df_g3["count"].between(51,250), 'count group'] = 'C-Tier 51-250'
df_g3.loc[df_g3["count"].between(251,1000), 'count group'] = 'B-Tier 251-1000'
df_g3.loc[df_g3["count"] > 1000, 'count group'] = 'A-Tier 1001+'

df_g3.sort_values(by = ['sorting', 'count group'], axis=0, ascending=True, inplace=True)

df_g3
Out[60]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count fundingrate prozent p_size sorting count group
112 nur Frauen Einzelperson Frau Albania 1353750.0 1295425.0 1272.519646 1175.0 1018 95.69 0.1529 742.506056 1.0 A-Tier 1001+
113 nur Frauen Einzelperson Frau Armenia 8454150.0 7677925.0 1426.328256 1275.0 5383 90.82 0.8087 530.395707 1.0 A-Tier 1001+
118 nur Frauen Einzelperson Frau Bolivia 5075250.0 4701600.0 1258.795181 1025.0 3735 92.64 0.5611 601.450652 1.0 A-Tier 1001+
121 nur Frauen Einzelperson Frau Cambodia 6123600.0 5894325.0 807.663058 700.0 7298 96.26 1.0964 772.324834 1.0 A-Tier 1001+
122 nur Frauen Einzelperson Frau Cameroon 515350.0 508300.0 396.489860 350.0 1282 98.63 0.1926 909.703781 1.0 A-Tier 1001+
... ... ... ... ... ... ... ... ... ... ... ... ... ...
527 unbekannt Unbekannt The Democratic Republic of the Congo 6000.0 3350.0 1116.666667 650.0 3 55.83 0.0005 47.304232 12.0 F-Tier 1-10
529 unbekannt Unbekannt Togo 10550.0 10550.0 1507.142857 1150.0 7 100.00 0.0011 1000.000000 12.0 F-Tier 1-10
530 unbekannt Unbekannt Turkey 22150.0 22150.0 11075.000000 11075.0 2 100.00 0.0003 1000.000000 12.0 F-Tier 1-10
533 unbekannt Unbekannt Vietnam 775.0 775.0 387.500000 387.5 2 100.00 0.0003 1000.000000 12.0 F-Tier 1-10
534 unbekannt Unbekannt Yemen 12125.0 12125.0 2425.000000 750.0 5 100.00 0.0008 1000.000000 12.0 F-Tier 1-10

537 rows × 13 columns

In [61]:
# Dummy Einträge Workaround. Dies verhindert das im Geoplot bestimmte Datenpunkte wärend der Animation nicht erneuert werden.
# Dies geschieht wenn keine Einträge für die jeweilige Kategoriecombo da sind. Die Einträger der vorherigen Kombo bleiben
# dann fehlerhaft in der internen Darstellungsmatrix erhalten und erscheinen so in der Legende und im Plot. 
# Damit kann man zwar nicht den ganzen Formatierungsfehler in der Legende beseitigen. Dieser ist aber nicht wirklich störend.

# Neue Copie für die Korrektur erstellen
df_g3_d = df_g3.copy()
In [62]:
#Erstellen der Dummywerte in einem Dict und einlesen in einen DataFrame
dict = {
        'group_class':['Einzelperson Frau', 'Einzelperson Man', 
                       'Kleine Gruppe (2-4) nur Frauen', 'Kleine Gruppe (2-4) nur Männer', 'Kleine Gruppe (2-4) gemischt',
                       'Mittlere Gruppe (5-8) nur Frauen', 'Mittlere Gruppe (5-8) nur Männer', 'Mittlere Gruppe (5-8) gemischt',
                       'Große Gruppe (9+) nur Frauen', 'Große Gruppe (9+) nur Männer', 'Große Gruppe (9+) gemischt',
                       'Unbekannt',
                      ]*5,
        'group_gender':['nur Frauen', 'nur Männer', 'nur Frauen', 'nur Männer', 'gemischt', 
                        'nur Frauen', 'nur Männer', 'gemischt', 
                        'nur Frauen', 'nur Männer', 'gemischt', 'unbekannt']*5,
        'country':['X']*60,
        'p_size':[0]*60,
        'count group':['A-Tier 1001+'] * 12 +
                      ['B-Tier 251-1000'] * 12 +
                      ['C-Tier 51-250'] * 12 +
                      ['D-Tier 11-50'] * 12 +
                      ['F-Tier 1-10'] * 12
       }
df_temp = pd.DataFrame(dict)
df_temp.head()
Out[62]:
group_class group_gender country p_size count group
0 Einzelperson Frau nur Frauen X 0 A-Tier 1001+
1 Einzelperson Man nur Männer X 0 A-Tier 1001+
2 Kleine Gruppe (2-4) nur Frauen nur Frauen X 0 A-Tier 1001+
3 Kleine Gruppe (2-4) nur Männer nur Männer X 0 A-Tier 1001+
4 Kleine Gruppe (2-4) gemischt gemischt X 0 A-Tier 1001+
In [63]:
# Anfügen der Dummywerte in die neue Kopie des DataFrames
df_g3_d = pd.concat([df_g3_d, df_temp], ignore_index = True)
df_g3_d
Out[63]:
group_gender group_class country sum_loans sum_funding mean_funding median_funding count fundingrate prozent p_size sorting count group
0 nur Frauen Einzelperson Frau Albania 1353750.0 1295425.0 1272.519646 1175.0 1018.0 95.69 0.1529 742.506056 1.0 A-Tier 1001+
1 nur Frauen Einzelperson Frau Armenia 8454150.0 7677925.0 1426.328256 1275.0 5383.0 90.82 0.8087 530.395707 1.0 A-Tier 1001+
2 nur Frauen Einzelperson Frau Bolivia 5075250.0 4701600.0 1258.795181 1025.0 3735.0 92.64 0.5611 601.450652 1.0 A-Tier 1001+
3 nur Frauen Einzelperson Frau Cambodia 6123600.0 5894325.0 807.663058 700.0 7298.0 96.26 1.0964 772.324834 1.0 A-Tier 1001+
4 nur Frauen Einzelperson Frau Cameroon 515350.0 508300.0 396.489860 350.0 1282.0 98.63 0.1926 909.703781 1.0 A-Tier 1001+
... ... ... ... ... ... ... ... ... ... ... ... ... ...
592 gemischt Mittlere Gruppe (5-8) gemischt X NaN NaN NaN NaN NaN NaN NaN 0.000000 NaN F-Tier 1-10
593 nur Frauen Große Gruppe (9+) nur Frauen X NaN NaN NaN NaN NaN NaN NaN 0.000000 NaN F-Tier 1-10
594 nur Männer Große Gruppe (9+) nur Männer X NaN NaN NaN NaN NaN NaN NaN 0.000000 NaN F-Tier 1-10
595 gemischt Große Gruppe (9+) gemischt X NaN NaN NaN NaN NaN NaN NaN 0.000000 NaN F-Tier 1-10
596 unbekannt Unbekannt X NaN NaN NaN NaN NaN NaN NaN 0.000000 NaN F-Tier 1-10

597 rows × 13 columns

Plot 3 zum bewerten¶

In [64]:
# Darstellen der Daten in einem geo Scatterplot
fig_m1 = px.scatter_geo(
    df_g3_d,
    # Festlegen der Markerkoordinaten
    locations="country",
    locationmode="country names",
    
    # Festlegen und Formatieren des Hovertextfeldes
    hover_data={ 
        'p_size': False,
        'country': True,
        'fundingrate': True,
        'count': True,
        'prozent': True,
        'group_class': True,
        'group_gender': False,
        'count group': True,
        'sum_funding': ':.2f',
        'mean_funding': ':.2f',
        'median_funding': ':.2f'
    },
    # Festlegen der Symbolgröße. p_size ist eine vorherig berechnete Hilfvariable um Unterschiede besser hervorzuheben
    size="p_size",
    # Erstellen des Animationsframes
    animation_frame="group_class",
    # Festlegen der Weltkarte
    projection='equirectangular',
    # Festlegen der Farblichen Kodierung der Gruppenzusammenstellung
    color='group_gender',
    color_discrete_map={
        'nur Frauen': '#fc0377',
        'nur Männer': '#0362fc',
        'gemischt': '#ce03fc',
        'unbekannt': '#27c71c'
    },
    size_max=7,
    height=600,
    labels={
        'country': 'Land',
        'count': 'Anzahl der Gruppen',
        'prozent': 'Prozent von allen Gruppen',
        'fundingrate': 'Prozent erfolgreiche Fundings',
        'group_class': 'Kategorie',
        'group_gender': 'Gruppentyp',
        'count group': 'Funding Anträge',
        'sum_funding': 'Gesamtsumme($) erfolgreicher Fundings',
        'mean_funding': 'Durchschnitt($) erfolgreicher Fundings',
        'median_funding': 'Median($) erfolgreicher Fundings'
    },
    title=
    "Weltkarte: Darstellung der Erfolgsquote von Fundings in jedem Land für einzelne Zielgruppen",
    # Festlegen der Symole. Diese geben die Anzahl der Anträge wieder für jedes Land. Diese Info ist sinnvoll
    # da oft Länder mit sehr wenigen Anträgen 100% Erfolgquote haben und so einen falschen Eindruck erwecken könnten.
    symbol='count group',
    symbol_map={
        'F-Tier 1-10': 'circle',
        'D-Tier 11-50': 'star-triangle-up',
        'C-Tier 51-250': 'star-diamond',
        'B-Tier 251-1000': 'star-dot',
        'A-Tier 1001+': 'star'
    },
)

#fig_m1.update_layout(showlegend=False)
#print(fig_m1)

fig_m1.show()

Erleuterung zum Plot¶

In der obrigen Darstellung wird die geographische Verteilung der einzelnen Gruppen deutlich sichtbar. In der unteren Leiste können die einzelnen Kategorien ausgewählt werden.

Die Größe der Symbole stellt die Fundingquota dar. Der Effekt ist überzeichnet und nicht vollständig quantitativ representativ, da in den meisten Fällen kein großer Unterschied besteht und so ohne eine visuelle Anpassung es schwierig ist qualitative Aussagen im oberen Bereich zu machen.

Die Symbolart stellt eine weitere Kategorisierung der Kundenkategorien nach den Ursprungsländern dar. Es wird unterteilt wie viele Anträge insgesammt aus den jeweiligen Ländern kommen. Diese Info ist sinnvoll da oft Länder mit sehr wenigen Anträgen 100% Erfolgquote haben und so einen falschen Eindruck erwecken könnten. Es werden dabei 5 Unterteilungen gemacht. Der Name der Kategorien orientiert sich an Schulnoten und ist rein wilkürlicht. Praktisch erlaubt er eine bessere Sortierbarkeit und Übersicht der zusammengesetzten Kundenkategorien. Ist das Symbol in der Legende für eine Kundenkategorie ausgeblendet gibt es keine solchen Fälle.

  • A-Tier (1001+)
  • B-Tier (251-1000)
  • C-Tier (51-250)
  • D-Tier (11-50)
  • F-Tier (1-10)

Im Hovertext sind weitere Metriken und Kenzahlen dargestellt:

  • Funding Anträge Tier
  • Gruppen Kategorie
  • Land
  • Prozent erfolgreiche Fundings
  • Anzahl der Gruppen die einen Funding beantragt haben
  • Prozentsatz der Anzahl der Gruppen zur Gesamtsumme aller weltweiten Gruppen
  • Gesamtsumme in Dollar erfolgreicher Fundings
  • Durchschnittlicher Fundingbetrag in Dollar
  • Median Fundingbetrag in Dollar

Analyse des Polts¶

Bei der Analyse des Plots lassen sich folgende Beobachtungen machen:

Afrika

  • Viele Projekte sind in Afrika beheimatet. Insbesondere Sub-Sahara West und Ostafrika. Bis auf Egypten ist Nordafrika nicht vertrehten.
  • Bis auf Mali, Senegal und Somalia sind in der Einzelperson Kategorie Frauen in der Mehrzahl.
  • Kenia hat mit über 70k Projekten sehr viele Projekte selbst Global betrachtet.
  • Es gibt viele Projekte von reinen Frauen und gemischten Gruppen über die gesamte Bandbreite, Gruppen nur aus Männern sind vorhanden aber weitaus seltener. Tanzania hat hier noch die meisten rein mänlichen Gruppen.
  • Trotz der mänlichen Dominanz in der Kategorie Einzelpersonen sind in Mali und Senegal sehr viele große reine Frauengruppen zu finden.
  • Insgesamt sind in West und Mittelafrika viele große Gruppen mit weiblicher Beteiligung zu finden.
  • Die Fundingquoten variieren stark von Land zu Land. Nicht immer stehen größere Gruppen besser dar. Der Trent das Frauen eine höhere Fundingrate haben als Männer zeigt sich trotzdem, selbst wenn die Baseline insgesamt niedriger ist.

Mittelamerika und Karibik

  • Das Verhältniss zwischen Männern und Frauen in der Kategorie Einzelpersonen ist hier wesendlich ausgeglichener. Es gibt einige Länder in denen das Verhältniss nahe an 50/50 liegt.
  • Bei Gruppen dominieren allerdings reine Frauengruppen und gemische Gruppen weiterhin.
  • Einzelne Frauen sind deutlich erfolgreicher als einzelne Männer trotz ähnlicher Beteiligungen.
  • Es gibt nur wenige reine Männergruppen.
  • El Salvador ist mit fast 40k Projekten viel stärker beteiligt als die Nachbarländer. Die Erfogsquote dort ist auch stark unterdurchschnittlich. Zudem gibt es kaum Gruppen. Damit unterscheidet es sich deutlich.
  • Der Effekt das größere Gruppen einen höhere Erfolgsquote haben ist nicht deutlich erkennbar. Einzelne Frauen sind teilweise erfolgreicher als Gruppen mit weiblicher Beteiligung.

Süd Amerika

  • Änlich wie in Mittelamerika ist das Verhältniss zwischen einzelnen Frauen und Männern ausgeglichener. Ebenfalls sind Frauen deutlich erfolgreicher beim Funding.
  • Kolumbien, Equador und Peru haben eine deutlich höhere Anzahl von Projekten als der Rest.
  • Es gibt nur sehr wenige kleine Gruppen aber deutlich mehr große Gruppen.
  • Die meisten Gruppen haben weibliche Beteiligung. Sie sind ungefähr gleich erfolgreich wie Einzelpersonen wenn nicht sogar erfolgreicher. Dies steht im Gegensatz zu dem gemischteren Bild das sich von Mittelamerika ergibt.

Balkan, Türkei und Kaukasus

  • Das Geschlechterverhältniss von Einzelpersonen ist hier ausgeglichener.
  • Frauen sind deutlich erfolgreicher als Männer.
  • Die Türkei bildet eine große Ausnahme. Hier gibt es keine mänliche Beteiligung. Vieleicht gibt es hier organisatorische Besonderheiten bei den Kreditvergabepartnern? Dies kann durch unsere Daten nicht ermittelt werden.
  • Armenien hat deutlich mehr Projekte als der Rest aber nur unterdurchschnittle Erfolgsquoten, insbesondere für Männer.
  • Es gibt zudem bis auf einen Einzelfall keine Gruppen egal welcher Zusammensetzung.

Naher Osten

  • In Libanon, Israel und Jordanien gibt es mehr einzelne Frauen als Männer als Antragsteller.
  • In den anderen umliegenden Staaten überwiegen Männer. Dies gilt besonders für Palestinia.
  • Ausser in Palestinia und Jordanien, in denen Frauen deutlich erfolgreicher sind, spielt hier das Geschecht des Antragstellers weniger eine Rolle.
  • Es gibt in der Region einige Kleingruppen, die meisten in Libanon, aber keine größeren Gruppen.

Indien und Zentralasien

  • Frauen ob einzeln oder als Gruppe sind hier sehr dominant. Sie machen auch Global betrachtet eine größere Gruppe aus.
  • Bis auf Tajikistan mit c.a 25% mänlicher Beteiligung, gibt es nur 10% oder deutlich weniger mänliche Antragsteller. Dies gilt besonders für Pakistan, Indien und Nepal.
  • Indien und Nepal haben eine 99% Erfolgsquote für Einzelpersonen, aber Gruppen haben hier eine schlechtere Quote. Größere Gruppen sind fast nur in Indien zu finden.
  • Pakistan hat mit über 25K die meisten Projekte in der Region

China und Mongolei

  • Trotz der Größe ist China mit insgesammt 133 Projekten global sehr unterrepresentiert. Mongolien ist als recht dünn besiedeltes Land mit 960 Projekten mehr als 7 mal stärker beteiligt.
  • In beiden Länder überwiegen einzelne Männer gegenüber einzelnen Frauen.
  • Alle Projekte in China wurden auch Finanziert. Auch die Mongolei hat überdurchschnittlich gute Erfolgsquoten.

Südostasien

  • In Vietnam und Kambodia gibt es sowol als Einzelperson als auch als Gruppen einen deutlich höheren Frauenanteil. Dies ist in den umgebenden Ländern ehr umgekehrt.
  • Männer und Frauen sind ähnlich erfolgreich.
  • Es gibt insbesondere in Kambodia mit über 22k Gruppenprojekten sehr viele kleine bis mittlere Gruppen. Dies macht einen großen Anteil an den globalen Gruppen aus. Dies gilt auch deutlich schwächer für Vietnam. Laos hat so gut wie keine kleinen Gruppen aber eine deutliche Spitze bei den großen gemischten Gruppen.
  • Die Gruppen in Laos sind auch sehr erfolgreich in ihrem Funding. Die Gruppen in Kambodia und Vietnam hingegen sind nur unterdurchschnittlich erfolgreich.

Philipinen, Indonesien und Ozeanien

  • Frauen haben hier eine dominantere Stellung. Sie sind auch erfolgreicher als die mänlichen Antragsteller.
  • Über 150k Projekte von Frauen kommen aus den Philipinen. Damit sind sie auch global sehr stark vertehten.
  • Gruppen gibt es fast ausschlieslich in Indonesien. Diese sind dort auch erfolgreicher als Einzelpersonen.

USA

  • In den USA gibt es mehr Frauen als Männer die einen Antrag stellen. Allerdings nicht so deutlich mit 56%.
  • Es gibt fast keine Gruppen in den USA.
  • Die Fundingerfolgsquote ist sehr schlecht mit 77% für Frauen, 69% für Männer. Dies ist eine deutliche Ausnahme.
  • Der durschnittliche im Funding erreiche Betrag ist mindestens 3x so hoch wie in den andenen Ländern.
  • Die USA unterscheidet sich damit sehr stark vom Rest. Ich empfehle daher das sie seperat betrachtet wird.

Fazit

  • Das Golbal beobachtete starke Übergewicht von Frauen bei den Projekten liegt hauptsächlich daran das Länder mit sehr starker Beteiligung auch eine sehr starkes Frauenübergewicht haben. In vielen Ländern ist das nicht so stark beobachtbar und teilweise sogar umgetreht.
  • Nicht immer sind größere Gruppen auch erfolgreicher. Dies ist stark Länderspezifisch. Zudem sind nicht in allen Ländern Gruppenprojekte vorhanden.
  • Daher empfehle ich das jedes Land idealerweise seperat betrachtet wird wenn es darum geht Buissness Strategien im Hinblick auf Kundenkategorien zu entwickeln

Ausblick und weitere Fragen

  • Wie könnte der Fundingerfolg von Männern gesteigert werden?
  • Viele Länder sind ehr unterrepresentiert. Wie könnte man hier mehr Projekte realisieren?
  • Einige Länder haben trotz vieler Projekte eine schlechte Erfolgsquote. Wie könnte man diese verbessern?
  • Wie sollte man mit den USA umgehen?

Dashboard¶

Ein interaktives Dasboard mit Dash das den ersten Plot um eine Länderauswahl erweitert.

In [65]:
# für die Dash-App
from dash import Dash

from dash import dcc
#import dash_core_components as dcc 

from dash import html
#import dash_html_components as html 

from dash.dependencies import Input, Output
from dash import no_update
In [66]:
# App erstellen
app = Dash(__name__)

# Layout festlegen

app.layout = html.Div(children=[#Überschrift
                                html.H1("Verteilung der Zielgruppen per Länderauswahl",
                                           style={"text-align" : "center"}
                                           ),
                                dcc.Dropdown(
                                                id="dd_land",
                                                options=sorted(df_g3["country"].unique()),   
                                                multi=True,   # Beachte: Rückgabewert ist eine Liste
                                                style={"width":260}
                                                ),
                                dcc.Graph(id="bar_dash")  
    
                                ]
                     )
# Callback erstellen
@app.callback(Output(component_id="bar_dash", component_property="figure"), # Rückgabe ist ein go.fig Dict
              Input(component_id='dd_land', component_property="value")) # Da Multiauswahl: Liste
def draw_figure(land_list):
    # Ist die Liste leer dann mach auch nix mit dem Plot
    if land_list is None:
        return no_update
    # Plot aus der Univariaten Analyse. Leicht angepasst für die Länderauswahl
    else:
        df_select = df_g3.loc[df_g3.loc[:,"country"].isin(land_list)]
        fig_dash = px.bar(df_select, x='group_class', y='count',
             color='group_gender',
             color_discrete_map= {'nur Frauen':'#fc0377', 'nur Männer': '#0362fc', 'gemischt': '#ce03fc', 'unbekannt': '#27c71c'},
             labels={'group_class':'Gruppenaufteilung','count':'Anzahl Debitoren', 'group_gender':'Zusammensetzung' }, 
             height=600,
             text = 'count'
               )

        fig_dash.update_yaxes(type="log")
        fig_dash.update_xaxes(categoryorder="array")
        fig_dash.update_xaxes(categoryarray=order)

        fig_dash.add_vline(x=1.5)
        fig_dash.add_vline(x=4.5)
        fig_dash.add_vline(x=7.5)
        fig_dash.add_vline(x=10.5)

        fig_dash.add_annotation(x=0.5, y=5.8,
                    text="Einzelpersonen",
                    font={'size': 14},
                    showarrow=False,
                    yshift=0)
        fig_dash.add_annotation(x=3, y=5.8,
                    text="Gruppengröße 2-4",
                    font={'size': 16},
                    showarrow=False,
                    yshift=0)
        fig_dash.add_annotation(x=6, y=5.8,
                    text="Gruppengröße 5-8",
                    font={'size': 16},
                    showarrow=False,
                    yshift=0)
        fig_dash.add_annotation(x=9, y=5.8,
                    text="Gruppengröße 9+",
                    font={'size': 16},
                    showarrow=False,
                    yshift=0)
        fig_dash.update_xaxes(showticklabels=False)    
    
        return fig_dash

# Dash Server für app starten    
app.run(jupyter_mode="external", port=8889)
Dash app running on http://127.0.0.1:8889/
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: